diff --git a/docs/dev/traceability.md b/docs/dev/traceability.md
index 9c906f7..dad7d14 100644
--- a/docs/dev/traceability.md
+++ b/docs/dev/traceability.md
@@ -10,7 +10,7 @@ Denominators are parsed from [`requirements.md`](requirements.md) at run time, n
| Metric | Value |
|---|---|
| Source files scanned | 434 |
-| TRACES tags found | 1572 |
+| TRACES tags found | 1573 |
| Requirements defined | 184 |
| Requirements deferred (post-v1) | 24 |
| Requirements covered | 154 |
@@ -35,72 +35,72 @@ A tag naming an ID `requirements.md` does not define — what renumbering produc
| 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:129`](../../core/dr-sync/src/scan.rs#L129), [`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/mod.rs:1`](../../ui/dr-ui/src/library/mod.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:377`](../../core/dr-types/src/settings.rs#L377), [`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:1790`](../../ui/dr-ui/src/lib.rs#L1790), [`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:1790`](../../ui/dr-ui/src/lib.rs#L1790), [`ui/dr-ui/src/library/filters.rs:12`](../../ui/dr-ui/src/library/filters.rs#L12), [`ui/dr-ui/src/library/thumbnails_gen.rs:518`](../../ui/dr-ui/src/library/thumbnails_gen.rs#L518), [`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:377`](../../core/dr-types/src/settings.rs#L377), [`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:1791`](../../ui/dr-ui/src/lib.rs#L1791), [`ui/dr-ui/ui/import.slint:5`](../../ui/dr-ui/ui/import.slint#L5), [`ui/dr-ui/ui/library.slint:1249`](../../ui/dr-ui/ui/library.slint#L1249), [`ui/dr-ui/ui/library.slint:1303`](../../ui/dr-ui/ui/library.slint#L1303), [`ui/dr-ui/ui/library.slint:1524`](../../ui/dr-ui/ui/library.slint#L1524) |
+| 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:1791`](../../ui/dr-ui/src/lib.rs#L1791), [`ui/dr-ui/src/library/filters.rs:12`](../../ui/dr-ui/src/library/filters.rs#L12), [`ui/dr-ui/src/library/thumbnails_gen.rs:518`](../../ui/dr-ui/src/library/thumbnails_gen.rs#L518), [`ui/dr-ui/ui/import.slint:5`](../../ui/dr-ui/ui/import.slint#L5) |
| FR-CAT-12 | [`core/dr-pipeline/src/sidecar.rs:137`](../../core/dr-pipeline/src/sidecar.rs#L137) |
-| FR-CAT-13 | [`core/dr-catalog/src/rating.rs:278`](../../core/dr-catalog/src/rating.rs#L278), [`core/dr-catalog/src/schema.rs:836`](../../core/dr-catalog/src/schema.rs#L836), [`core/dr-sync/src/scan.rs:40`](../../core/dr-sync/src/scan.rs#L40), [`core/dr-sync/src/scan.rs:944`](../../core/dr-sync/src/scan.rs#L944), [`core/dr-types/src/settings.rs:92`](../../core/dr-types/src/settings.rs#L92), [`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), [`ui/dr-ui/src/library/scan.rs:335`](../../ui/dr-ui/src/library/scan.rs#L335), [`ui/dr-ui/src/library/xmp.rs:132`](../../ui/dr-ui/src/library/xmp.rs#L132), [`ui/dr-ui/src/library/xmp.rs:25`](../../ui/dr-ui/src/library/xmp.rs#L25), [`ui/dr-ui/src/library/xmp.rs:9`](../../ui/dr-ui/src/library/xmp.rs#L9), [`ui/dr-ui/src/library_ui/controller.rs:296`](../../ui/dr-ui/src/library_ui/controller.rs#L296), [`ui/dr-ui/src/library_ui/controller.rs:387`](../../ui/dr-ui/src/library_ui/controller.rs#L387), [`ui/dr-ui/src/library_ui/controller.rs:532`](../../ui/dr-ui/src/library_ui/controller.rs#L532), [`ui/dr-ui/src/library_ui/grid.rs:156`](../../ui/dr-ui/src/library_ui/grid.rs#L156), [`ui/dr-ui/src/library_ui/open.rs:423`](../../ui/dr-ui/src/library_ui/open.rs#L423), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:503`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L503), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:559`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L559), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:657`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L657), [`ui/dr-ui/src/settings_ui.rs:558`](../../ui/dr-ui/src/settings_ui.rs#L558), [`ui/dr-ui/src/xmp_sync.rs:1`](../../ui/dr-ui/src/xmp_sync.rs#L1), [`ui/dr-ui/src/xmp_sync.rs:250`](../../ui/dr-ui/src/xmp_sync.rs#L250), [`ui/dr-ui/src/xmp_sync.rs:287`](../../ui/dr-ui/src/xmp_sync.rs#L287), [`ui/dr-ui/src/xmp_sync.rs:324`](../../ui/dr-ui/src/xmp_sync.rs#L324), [`ui/dr-ui/ui/app.slint:856`](../../ui/dr-ui/ui/app.slint#L856), [`ui/dr-ui/ui/settings.slint:1093`](../../ui/dr-ui/ui/settings.slint#L1093), [`ui/dr-ui/ui/settings.slint:199`](../../ui/dr-ui/ui/settings.slint#L199) |
-| FR-CAT-15 | [`core/dr-catalog/src/schema.rs:1210`](../../core/dr-catalog/src/schema.rs#L1210), [`core/dr-catalog/src/trash.rs:1`](../../core/dr-catalog/src/trash.rs#L1), [`core/dr-sync-nextcloud/src/lib.rs:522`](../../core/dr-sync-nextcloud/src/lib.rs#L522), [`core/dr-sync/src/lib.rs:135`](../../core/dr-sync/src/lib.rs#L135), [`core/dr-sync/src/scan.rs:618`](../../core/dr-sync/src/scan.rs#L618), [`core/dr-sync/src/scan.rs:93`](../../core/dr-sync/src/scan.rs#L93), [`core/dr-thumbs/src/lib.rs:393`](../../core/dr-thumbs/src/lib.rs#L393), [`core/dr-types/src/place.rs:91`](../../core/dr-types/src/place.rs#L91), [`ui/dr-ui/src/collections_ui/trash.rs:82`](../../ui/dr-ui/src/collections_ui/trash.rs#L82), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:798`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L798), [`ui/dr-ui/src/library/cells.rs:158`](../../ui/dr-ui/src/library/cells.rs#L158), [`ui/dr-ui/src/library/cells.rs:192`](../../ui/dr-ui/src/library/cells.rs#L192), [`ui/dr-ui/src/library/filters.rs:12`](../../ui/dr-ui/src/library/filters.rs#L12), [`ui/dr-ui/src/library/filters.rs:29`](../../ui/dr-ui/src/library/filters.rs#L29), [`ui/dr-ui/src/library/filters.rs:59`](../../ui/dr-ui/src/library/filters.rs#L59), [`ui/dr-ui/src/library_ui/controller.rs:232`](../../ui/dr-ui/src/library_ui/controller.rs#L232), [`ui/dr-ui/src/library_ui/controller.rs:909`](../../ui/dr-ui/src/library_ui/controller.rs#L909), [`ui/dr-ui/src/trash.rs:1`](../../ui/dr-ui/src/trash.rs#L1), [`ui/dr-ui/ui/collections.slint:1182`](../../ui/dr-ui/ui/collections.slint#L1182), [`ui/dr-ui/ui/collections.slint:745`](../../ui/dr-ui/ui/collections.slint#L745) |
+| FR-CAT-13 | [`core/dr-catalog/src/rating.rs:278`](../../core/dr-catalog/src/rating.rs#L278), [`core/dr-catalog/src/schema.rs:836`](../../core/dr-catalog/src/schema.rs#L836), [`core/dr-sync/src/scan.rs:40`](../../core/dr-sync/src/scan.rs#L40), [`core/dr-sync/src/scan.rs:944`](../../core/dr-sync/src/scan.rs#L944), [`core/dr-types/src/settings.rs:92`](../../core/dr-types/src/settings.rs#L92), [`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), [`ui/dr-ui/src/library/scan.rs:335`](../../ui/dr-ui/src/library/scan.rs#L335), [`ui/dr-ui/src/library/xmp.rs:132`](../../ui/dr-ui/src/library/xmp.rs#L132), [`ui/dr-ui/src/library/xmp.rs:25`](../../ui/dr-ui/src/library/xmp.rs#L25), [`ui/dr-ui/src/library/xmp.rs:9`](../../ui/dr-ui/src/library/xmp.rs#L9), [`ui/dr-ui/src/library_ui/controller.rs:296`](../../ui/dr-ui/src/library_ui/controller.rs#L296), [`ui/dr-ui/src/library_ui/controller.rs:387`](../../ui/dr-ui/src/library_ui/controller.rs#L387), [`ui/dr-ui/src/library_ui/controller.rs:532`](../../ui/dr-ui/src/library_ui/controller.rs#L532), [`ui/dr-ui/src/library_ui/grid.rs:156`](../../ui/dr-ui/src/library_ui/grid.rs#L156), [`ui/dr-ui/src/library_ui/open.rs:438`](../../ui/dr-ui/src/library_ui/open.rs#L438), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:529`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L529), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:585`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L585), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:683`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L683), [`ui/dr-ui/src/settings_ui.rs:558`](../../ui/dr-ui/src/settings_ui.rs#L558), [`ui/dr-ui/src/xmp_sync.rs:1`](../../ui/dr-ui/src/xmp_sync.rs#L1), [`ui/dr-ui/src/xmp_sync.rs:250`](../../ui/dr-ui/src/xmp_sync.rs#L250), [`ui/dr-ui/src/xmp_sync.rs:287`](../../ui/dr-ui/src/xmp_sync.rs#L287), [`ui/dr-ui/src/xmp_sync.rs:324`](../../ui/dr-ui/src/xmp_sync.rs#L324), [`ui/dr-ui/ui/app.slint:599`](../../ui/dr-ui/ui/app.slint#L599), [`ui/dr-ui/ui/settings.slint:1093`](../../ui/dr-ui/ui/settings.slint#L1093), [`ui/dr-ui/ui/settings.slint:199`](../../ui/dr-ui/ui/settings.slint#L199) |
+| FR-CAT-15 | [`core/dr-catalog/src/schema.rs:1210`](../../core/dr-catalog/src/schema.rs#L1210), [`core/dr-catalog/src/trash.rs:1`](../../core/dr-catalog/src/trash.rs#L1), [`core/dr-sync-nextcloud/src/lib.rs:522`](../../core/dr-sync-nextcloud/src/lib.rs#L522), [`core/dr-sync/src/lib.rs:135`](../../core/dr-sync/src/lib.rs#L135), [`core/dr-sync/src/scan.rs:618`](../../core/dr-sync/src/scan.rs#L618), [`core/dr-sync/src/scan.rs:93`](../../core/dr-sync/src/scan.rs#L93), [`core/dr-thumbs/src/lib.rs:393`](../../core/dr-thumbs/src/lib.rs#L393), [`core/dr-types/src/place.rs:91`](../../core/dr-types/src/place.rs#L91), [`ui/dr-ui/src/collections_ui/trash.rs:84`](../../ui/dr-ui/src/collections_ui/trash.rs#L84), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:819`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L819), [`ui/dr-ui/src/library/cells.rs:158`](../../ui/dr-ui/src/library/cells.rs#L158), [`ui/dr-ui/src/library/cells.rs:192`](../../ui/dr-ui/src/library/cells.rs#L192), [`ui/dr-ui/src/library/filters.rs:12`](../../ui/dr-ui/src/library/filters.rs#L12), [`ui/dr-ui/src/library/filters.rs:29`](../../ui/dr-ui/src/library/filters.rs#L29), [`ui/dr-ui/src/library/filters.rs:59`](../../ui/dr-ui/src/library/filters.rs#L59), [`ui/dr-ui/src/library_ui/controller.rs:232`](../../ui/dr-ui/src/library_ui/controller.rs#L232), [`ui/dr-ui/src/library_ui/controller.rs:909`](../../ui/dr-ui/src/library_ui/controller.rs#L909), [`ui/dr-ui/src/trash.rs:1`](../../ui/dr-ui/src/trash.rs#L1), [`ui/dr-ui/ui/collections.slint:1182`](../../ui/dr-ui/ui/collections.slint#L1182), [`ui/dr-ui/ui/collections.slint:745`](../../ui/dr-ui/ui/collections.slint#L745) |
| 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:105`](../../core/dr-sync/src/scan.rs#L105), [`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/sweep.rs:557`](../../ui/dr-ui/src/library/sweep.rs#L557), [`ui/dr-ui/src/library_ui/controller.rs:171`](../../ui/dr-ui/src/library_ui/controller.rs#L171), [`ui/dr-ui/src/library_ui/grid.rs:443`](../../ui/dr-ui/src/library_ui/grid.rs#L443), [`ui/dr-ui/src/library_ui/sync.rs:363`](../../ui/dr-ui/src/library_ui/sync.rs#L363), [`ui/dr-ui/src/repairs.rs:1`](../../ui/dr-ui/src/repairs.rs#L1), [`ui/dr-ui/src/repairs.rs:687`](../../ui/dr-ui/src/repairs.rs#L687), [`ui/dr-ui/ui/app.slint:430`](../../ui/dr-ui/ui/app.slint#L430), [`ui/dr-ui/ui/settings.slint:435`](../../ui/dr-ui/ui/settings.slint#L435), [`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:564`](../../core/dr-catalog/src/schema.rs#L564), [`ui/dr-ui/src/library/filters.rs:39`](../../ui/dr-ui/src/library/filters.rs#L39), [`ui/dr-ui/src/library/mod.rs:1`](../../ui/dr-ui/src/library/mod.rs#L1), [`ui/dr-ui/src/library_ui/mod.rs:1`](../../ui/dr-ui/src/library_ui/mod.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:1125`](../../core/dr-catalog/src/schema.rs#L1125), [`core/dr-catalog/src/schema.rs:1682`](../../core/dr-catalog/src/schema.rs#L1682), [`core/dr-decode/src/lib.rs:301`](../../core/dr-decode/src/lib.rs#L301), [`core/dr-decode/src/lib.rs:307`](../../core/dr-decode/src/lib.rs#L307), [`core/dr-decode/src/lib.rs:317`](../../core/dr-decode/src/lib.rs#L317), [`core/dr-decode/src/lib.rs:444`](../../core/dr-decode/src/lib.rs#L444), [`core/dr-export/src/dng.rs:308`](../../core/dr-export/src/dng.rs#L308), [`core/dr-pipeline/src/sidecar.rs:171`](../../core/dr-pipeline/src/sidecar.rs#L171), [`ui/dr-ui/src/collections_ui/controller.rs:16`](../../ui/dr-ui/src/collections_ui/controller.rs#L16), [`ui/dr-ui/src/collections_ui/controller.rs:204`](../../ui/dr-ui/src/collections_ui/controller.rs#L204), [`ui/dr-ui/src/collections_ui/controller.rs:413`](../../ui/dr-ui/src/collections_ui/controller.rs#L413), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:146`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L146), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:256`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L256), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:315`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L315), [`ui/dr-ui/src/library/cells.rs:206`](../../ui/dr-ui/src/library/cells.rs#L206), [`ui/dr-ui/src/library_ui/controller.rs:784`](../../ui/dr-ui/src/library_ui/controller.rs#L784), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:1011`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L1011), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:1020`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L1020), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:972`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L972), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:983`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L983), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:996`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L996), [`ui/dr-ui/ui/app.slint:351`](../../ui/dr-ui/ui/app.slint#L351), [`ui/dr-ui/ui/app.slint:567`](../../ui/dr-ui/ui/app.slint#L567), [`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:4253`](../../ui/dr-ui/ui/library.slint#L4253) |
-| 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:1125`](../../core/dr-catalog/src/schema.rs#L1125), [`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/filters.rs:64`](../../ui/dr-ui/src/library/filters.rs#L64), [`ui/dr-ui/src/library/spans.rs:253`](../../ui/dr-ui/src/library/spans.rs#L253), [`ui/dr-ui/src/library_ui/controller.rs:391`](../../ui/dr-ui/src/library_ui/controller.rs#L391), [`ui/dr-ui/src/library_ui/controller.rs:500`](../../ui/dr-ui/src/library_ui/controller.rs#L500), [`ui/dr-ui/src/library_ui/filter_bar.rs:274`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L274), [`ui/dr-ui/src/library_ui/filter_bar.rs:327`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L327), [`ui/dr-ui/src/library_ui/filter_bar.rs:678`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L678), [`ui/dr-ui/ui/app.slint:363`](../../ui/dr-ui/ui/app.slint#L363), [`ui/dr-ui/ui/app.slint:567`](../../ui/dr-ui/ui/app.slint#L567), [`ui/dr-ui/ui/app.slint:852`](../../ui/dr-ui/ui/app.slint#L852), [`ui/dr-ui/ui/library.slint:111`](../../ui/dr-ui/ui/library.slint#L111), [`ui/dr-ui/ui/library.slint:1552`](../../ui/dr-ui/ui/library.slint#L1552), [`ui/dr-ui/ui/library.slint:4253`](../../ui/dr-ui/ui/library.slint#L4253), [`ui/dr-ui/ui/settings.slint:191`](../../ui/dr-ui/ui/settings.slint#L191) |
-| 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/controller.rs:258`](../../ui/dr-ui/src/collections_ui/controller.rs#L258), [`ui/dr-ui/src/collections_ui/controller.rs:268`](../../ui/dr-ui/src/collections_ui/controller.rs#L268), [`ui/dr-ui/src/collections_ui/controller.rs:291`](../../ui/dr-ui/src/collections_ui/controller.rs#L291), [`ui/dr-ui/src/collections_ui/controller.rs:312`](../../ui/dr-ui/src/collections_ui/controller.rs#L312), [`ui/dr-ui/src/collections_ui/controller.rs:46`](../../ui/dr-ui/src/collections_ui/controller.rs#L46), [`ui/dr-ui/src/collections_ui/drag.rs:274`](../../ui/dr-ui/src/collections_ui/drag.rs#L274), [`ui/dr-ui/src/collections_ui/mod.rs:1`](../../ui/dr-ui/src/collections_ui/mod.rs#L1), [`ui/dr-ui/src/collections_ui/press.rs:257`](../../ui/dr-ui/src/collections_ui/press.rs#L257), [`ui/dr-ui/src/collections_ui/press.rs:489`](../../ui/dr-ui/src/collections_ui/press.rs#L489), [`ui/dr-ui/src/collections_ui/press.rs:53`](../../ui/dr-ui/src/collections_ui/press.rs#L53), [`ui/dr-ui/src/collections_ui/rename_menu.rs:196`](../../ui/dr-ui/src/collections_ui/rename_menu.rs#L196), [`ui/dr-ui/src/collections_ui/rename_menu.rs:21`](../../ui/dr-ui/src/collections_ui/rename_menu.rs#L21), [`ui/dr-ui/src/collections_ui/tree_sync.rs:244`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L244), [`ui/dr-ui/src/collections_ui/tree_sync.rs:315`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L315), [`ui/dr-ui/src/collections_ui/tree_sync.rs:337`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L337), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:119`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L119), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:165`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L165), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:432`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L432), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:508`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L508), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:570`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L570), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:284`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L284), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:341`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L341), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:391`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L391), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:513`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L513), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:576`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L576), [`ui/dr-ui/src/derived_sync.rs:1`](../../ui/dr-ui/src/derived_sync.rs#L1), [`ui/dr-ui/src/library/spans.rs:139`](../../ui/dr-ui/src/library/spans.rs#L139), [`ui/dr-ui/src/library/spans.rs:58`](../../ui/dr-ui/src/library/spans.rs#L58), [`ui/dr-ui/src/library/spans.rs:84`](../../ui/dr-ui/src/library/spans.rs#L84), [`ui/dr-ui/src/library_ui/sync.rs:217`](../../ui/dr-ui/src/library_ui/sync.rs#L217), [`ui/dr-ui/src/library_ui/timeline.rs:492`](../../ui/dr-ui/src/library_ui/timeline.rs#L492), [`ui/dr-ui/src/library_ui/window.rs:271`](../../ui/dr-ui/src/library_ui/window.rs#L271), [`ui/dr-ui/ui/app.slint:3169`](../../ui/dr-ui/ui/app.slint#L3169), [`ui/dr-ui/ui/app.slint:354`](../../ui/dr-ui/ui/app.slint#L354), [`ui/dr-ui/ui/app.slint:562`](../../ui/dr-ui/ui/app.slint#L562), [`ui/dr-ui/ui/app.slint:591`](../../ui/dr-ui/ui/app.slint#L591), [`ui/dr-ui/ui/collections.slint:1182`](../../ui/dr-ui/ui/collections.slint#L1182), [`ui/dr-ui/ui/collections.slint:4`](../../ui/dr-ui/ui/collections.slint#L4), [`ui/dr-ui/ui/collections.slint:587`](../../ui/dr-ui/ui/collections.slint#L587), [`ui/dr-ui/ui/library.slint:1327`](../../ui/dr-ui/ui/library.slint#L1327), [`ui/dr-ui/ui/library.slint:2949`](../../ui/dr-ui/ui/library.slint#L2949), [`ui/dr-ui/ui/library.slint:4231`](../../ui/dr-ui/ui/library.slint#L4231), [`ui/dr-ui/ui/library.slint:4318`](../../ui/dr-ui/ui/library.slint#L4318), [`ui/dr-ui/ui/library.slint:998`](../../ui/dr-ui/ui/library.slint#L998) |
-| FR-CAT-8 | [`core/dr-catalog/src/schema.rs:740`](../../core/dr-catalog/src/schema.rs#L740), [`core/dr-pipeline/src/coverage.rs:1`](../../core/dr-pipeline/src/coverage.rs#L1), [`core/dr-pipeline/src/graph.rs:587`](../../core/dr-pipeline/src/graph.rs#L587), [`core/dr-pipeline/src/graph.rs:640`](../../core/dr-pipeline/src/graph.rs#L640), [`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:1400`](../../core/dr-pipeline/src/sidecar.rs#L1400), [`core/dr-pipeline/src/sidecar.rs:2232`](../../core/dr-pipeline/src/sidecar.rs#L2232), [`core/dr-pipeline/src/sidecar.rs:96`](../../core/dr-pipeline/src/sidecar.rs#L96), [`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:56`](../../core/dr-sync/src/scan.rs#L56), [`core/dr-sync/src/scan.rs:926`](../../core/dr-sync/src/scan.rs#L926), [`ui/dr-ui/src/develop/mask_ops.rs:1076`](../../ui/dr-ui/src/develop/mask_ops.rs#L1076), [`ui/dr-ui/src/develop/mask_ops.rs:1130`](../../ui/dr-ui/src/develop/mask_ops.rs#L1130), [`ui/dr-ui/src/develop/mask_ops.rs:178`](../../ui/dr-ui/src/develop/mask_ops.rs#L178), [`ui/dr-ui/src/develop/masks.rs:740`](../../ui/dr-ui/src/develop/masks.rs#L740), [`ui/dr-ui/src/develop/session.rs:561`](../../ui/dr-ui/src/develop/session.rs#L561), [`ui/dr-ui/src/develop/session.rs:590`](../../ui/dr-ui/src/develop/session.rs#L590), [`ui/dr-ui/src/export.rs:812`](../../ui/dr-ui/src/export.rs#L812), [`ui/dr-ui/src/lib.rs:1183`](../../ui/dr-ui/src/lib.rs#L1183), [`ui/dr-ui/src/lib.rs:1243`](../../ui/dr-ui/src/lib.rs#L1243), [`ui/dr-ui/src/lib.rs:2691`](../../ui/dr-ui/src/lib.rs#L2691), [`ui/dr-ui/src/lib.rs:2838`](../../ui/dr-ui/src/lib.rs#L2838), [`ui/dr-ui/src/lib.rs:758`](../../ui/dr-ui/src/lib.rs#L758), [`ui/dr-ui/src/library/scan.rs:226`](../../ui/dr-ui/src/library/scan.rs#L226), [`ui/dr-ui/src/library/scan.rs:261`](../../ui/dr-ui/src/library/scan.rs#L261), [`ui/dr-ui/src/library/scan.rs:34`](../../ui/dr-ui/src/library/scan.rs#L34), [`ui/dr-ui/src/library/sidecar.rs:100`](../../ui/dr-ui/src/library/sidecar.rs#L100), [`ui/dr-ui/src/library/sidecar.rs:11`](../../ui/dr-ui/src/library/sidecar.rs#L11), [`ui/dr-ui/src/library/sidecar.rs:373`](../../ui/dr-ui/src/library/sidecar.rs#L373), [`ui/dr-ui/src/library/sidecar.rs:63`](../../ui/dr-ui/src/library/sidecar.rs#L63), [`ui/dr-ui/src/library/thumbnails_fetch.rs:413`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L413), [`ui/dr-ui/src/library_ui/grid.rs:667`](../../ui/dr-ui/src/library_ui/grid.rs#L667), [`ui/dr-ui/src/library_ui/open.rs:440`](../../ui/dr-ui/src/library_ui/open.rs#L440), [`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:1182`](../../core/dr-catalog/src/schema.rs#L1182), [`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:35`](../../core/dr-sync-nextcloud/src/desktop_client.rs#L35), [`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:211`](../../core/dr-sync/src/scan.rs#L211), [`core/dr-sync/src/scan.rs:519`](../../core/dr-sync/src/scan.rs#L519), [`core/dr-types/src/lib.rs:122`](../../core/dr-types/src/lib.rs#L122), [`ui/dr-ui/src/develop/render.rs:584`](../../ui/dr-ui/src/develop/render.rs#L584), [`ui/dr-ui/src/develop/render.rs:627`](../../ui/dr-ui/src/develop/render.rs#L627), [`ui/dr-ui/src/library/filters.rs:84`](../../ui/dr-ui/src/library/filters.rs#L84), [`ui/dr-ui/src/library/scan.rs:126`](../../ui/dr-ui/src/library/scan.rs#L126), [`ui/dr-ui/src/library/scan.rs:179`](../../ui/dr-ui/src/library/scan.rs#L179), [`ui/dr-ui/src/library/scan.rs:210`](../../ui/dr-ui/src/library/scan.rs#L210), [`ui/dr-ui/src/library/scan.rs:261`](../../ui/dr-ui/src/library/scan.rs#L261), [`ui/dr-ui/src/library/scan.rs:605`](../../ui/dr-ui/src/library/scan.rs#L605), [`ui/dr-ui/src/library/sidecar.rs:100`](../../ui/dr-ui/src/library/sidecar.rs#L100), [`ui/dr-ui/src/library/sidecar.rs:357`](../../ui/dr-ui/src/library/sidecar.rs#L357), [`ui/dr-ui/src/library/sidecar.rs:373`](../../ui/dr-ui/src/library/sidecar.rs#L373), [`ui/dr-ui/src/library/sidecar.rs:427`](../../ui/dr-ui/src/library/sidecar.rs#L427), [`ui/dr-ui/src/library/spans.rs:361`](../../ui/dr-ui/src/library/spans.rs#L361), [`ui/dr-ui/src/library/thumbnails_fetch.rs:393`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L393), [`ui/dr-ui/src/library/thumbnails_fetch.rs:449`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L449), [`ui/dr-ui/src/library/thumbnails_gen.rs:74`](../../ui/dr-ui/src/library/thumbnails_gen.rs#L74), [`ui/dr-ui/src/library_ui/controller.rs:279`](../../ui/dr-ui/src/library_ui/controller.rs#L279), [`ui/dr-ui/src/library_ui/controller.rs:315`](../../ui/dr-ui/src/library_ui/controller.rs#L315), [`ui/dr-ui/src/library_ui/controller.rs:323`](../../ui/dr-ui/src/library_ui/controller.rs#L323), [`ui/dr-ui/src/library_ui/controller.rs:568`](../../ui/dr-ui/src/library_ui/controller.rs#L568), [`ui/dr-ui/src/library_ui/controller.rs:657`](../../ui/dr-ui/src/library_ui/controller.rs#L657), [`ui/dr-ui/src/library_ui/filter_bar.rs:380`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L380), [`ui/dr-ui/src/library_ui/filter_bar.rs:462`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L462), [`ui/dr-ui/src/library_ui/offline.rs:538`](../../ui/dr-ui/src/library_ui/offline.rs#L538), [`ui/dr-ui/src/library_ui/offline.rs:582`](../../ui/dr-ui/src/library_ui/offline.rs#L582), [`ui/dr-ui/src/library_ui/offline.rs:598`](../../ui/dr-ui/src/library_ui/offline.rs#L598), [`ui/dr-ui/src/library_ui/open.rs:507`](../../ui/dr-ui/src/library_ui/open.rs#L507), [`ui/dr-ui/src/library_ui/open.rs:583`](../../ui/dr-ui/src/library_ui/open.rs#L583), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:692`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L692), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:69`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L69), [`ui/dr-ui/src/library_ui/sync.rs:268`](../../ui/dr-ui/src/library_ui/sync.rs#L268), [`ui/dr-ui/src/library_ui/sync.rs:390`](../../ui/dr-ui/src/library_ui/sync.rs#L390), [`ui/dr-ui/src/library_ui/sync.rs:80`](../../ui/dr-ui/src/library_ui/sync.rs#L80), [`ui/dr-ui/src/library_ui/window.rs:545`](../../ui/dr-ui/src/library_ui/window.rs#L545), [`ui/dr-ui/src/library_ui/window.rs:823`](../../ui/dr-ui/src/library_ui/window.rs#L823), [`ui/dr-ui/src/presets.rs:486`](../../ui/dr-ui/src/presets.rs#L486), [`ui/dr-ui/src/presets.rs:498`](../../ui/dr-ui/src/presets.rs#L498), [`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-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:105`](../../core/dr-sync/src/scan.rs#L105), [`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/sweep.rs:557`](../../ui/dr-ui/src/library/sweep.rs#L557), [`ui/dr-ui/src/library_ui/controller.rs:171`](../../ui/dr-ui/src/library_ui/controller.rs#L171), [`ui/dr-ui/src/library_ui/grid.rs:458`](../../ui/dr-ui/src/library_ui/grid.rs#L458), [`ui/dr-ui/src/library_ui/sync.rs:368`](../../ui/dr-ui/src/library_ui/sync.rs#L368), [`ui/dr-ui/src/repairs.rs:1`](../../ui/dr-ui/src/repairs.rs#L1), [`ui/dr-ui/src/repairs.rs:687`](../../ui/dr-ui/src/repairs.rs#L687), [`ui/dr-ui/ui/library.slint:482`](../../ui/dr-ui/ui/library.slint#L482), [`ui/dr-ui/ui/library.slint:730`](../../ui/dr-ui/ui/library.slint#L730), [`ui/dr-ui/ui/settings.slint:435`](../../ui/dr-ui/ui/settings.slint#L435), [`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:564`](../../core/dr-catalog/src/schema.rs#L564), [`ui/dr-ui/src/library/filters.rs:39`](../../ui/dr-ui/src/library/filters.rs#L39), [`ui/dr-ui/src/library/mod.rs:1`](../../ui/dr-ui/src/library/mod.rs#L1), [`ui/dr-ui/src/library_ui/mod.rs:1`](../../ui/dr-ui/src/library_ui/mod.rs#L1), [`ui/dr-ui/ui/library.slint:482`](../../ui/dr-ui/ui/library.slint#L482) |
+| 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:1125`](../../core/dr-catalog/src/schema.rs#L1125), [`core/dr-catalog/src/schema.rs:1682`](../../core/dr-catalog/src/schema.rs#L1682), [`core/dr-decode/src/lib.rs:301`](../../core/dr-decode/src/lib.rs#L301), [`core/dr-decode/src/lib.rs:307`](../../core/dr-decode/src/lib.rs#L307), [`core/dr-decode/src/lib.rs:317`](../../core/dr-decode/src/lib.rs#L317), [`core/dr-decode/src/lib.rs:444`](../../core/dr-decode/src/lib.rs#L444), [`core/dr-export/src/dng.rs:308`](../../core/dr-export/src/dng.rs#L308), [`core/dr-pipeline/src/sidecar.rs:171`](../../core/dr-pipeline/src/sidecar.rs#L171), [`ui/dr-ui/src/collections_ui/controller.rs:16`](../../ui/dr-ui/src/collections_ui/controller.rs#L16), [`ui/dr-ui/src/collections_ui/controller.rs:204`](../../ui/dr-ui/src/collections_ui/controller.rs#L204), [`ui/dr-ui/src/collections_ui/controller.rs:413`](../../ui/dr-ui/src/collections_ui/controller.rs#L413), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:150`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L150), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:264`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L264), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:323`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L323), [`ui/dr-ui/src/library/cells.rs:206`](../../ui/dr-ui/src/library/cells.rs#L206), [`ui/dr-ui/src/library_ui/controller.rs:784`](../../ui/dr-ui/src/library_ui/controller.rs#L784), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:1012`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L1012), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:1023`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L1023), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:1036`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L1036), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:1051`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L1051), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:1060`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L1060), [`ui/dr-ui/ui/library.slint:1630`](../../ui/dr-ui/ui/library.slint#L1630), [`ui/dr-ui/ui/library.slint:1654`](../../ui/dr-ui/ui/library.slint#L1654), [`ui/dr-ui/ui/library.slint:1707`](../../ui/dr-ui/ui/library.slint#L1707), [`ui/dr-ui/ui/library.slint:19`](../../ui/dr-ui/ui/library.slint#L19), [`ui/dr-ui/ui/library.slint:4523`](../../ui/dr-ui/ui/library.slint#L4523), [`ui/dr-ui/ui/library.slint:482`](../../ui/dr-ui/ui/library.slint#L482), [`ui/dr-ui/ui/library.slint:504`](../../ui/dr-ui/ui/library.slint#L504), [`ui/dr-ui/ui/library.slint:603`](../../ui/dr-ui/ui/library.slint#L603) |
+| 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:1125`](../../core/dr-catalog/src/schema.rs#L1125), [`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/filters.rs:64`](../../ui/dr-ui/src/library/filters.rs#L64), [`ui/dr-ui/src/library/spans.rs:253`](../../ui/dr-ui/src/library/spans.rs#L253), [`ui/dr-ui/src/library_ui/controller.rs:391`](../../ui/dr-ui/src/library_ui/controller.rs#L391), [`ui/dr-ui/src/library_ui/controller.rs:500`](../../ui/dr-ui/src/library_ui/controller.rs#L500), [`ui/dr-ui/src/library_ui/filter_bar.rs:295`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L295), [`ui/dr-ui/src/library_ui/filter_bar.rs:350`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L350), [`ui/dr-ui/src/library_ui/filter_bar.rs:718`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L718), [`ui/dr-ui/ui/app.slint:595`](../../ui/dr-ui/ui/app.slint#L595), [`ui/dr-ui/ui/library.slint:111`](../../ui/dr-ui/ui/library.slint#L111), [`ui/dr-ui/ui/library.slint:1822`](../../ui/dr-ui/ui/library.slint#L1822), [`ui/dr-ui/ui/library.slint:4523`](../../ui/dr-ui/ui/library.slint#L4523), [`ui/dr-ui/ui/library.slint:482`](../../ui/dr-ui/ui/library.slint#L482), [`ui/dr-ui/ui/library.slint:603`](../../ui/dr-ui/ui/library.slint#L603), [`ui/dr-ui/ui/library.slint:652`](../../ui/dr-ui/ui/library.slint#L652), [`ui/dr-ui/ui/settings.slint:191`](../../ui/dr-ui/ui/settings.slint#L191) |
+| 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/controller.rs:258`](../../ui/dr-ui/src/collections_ui/controller.rs#L258), [`ui/dr-ui/src/collections_ui/controller.rs:268`](../../ui/dr-ui/src/collections_ui/controller.rs#L268), [`ui/dr-ui/src/collections_ui/controller.rs:291`](../../ui/dr-ui/src/collections_ui/controller.rs#L291), [`ui/dr-ui/src/collections_ui/controller.rs:312`](../../ui/dr-ui/src/collections_ui/controller.rs#L312), [`ui/dr-ui/src/collections_ui/controller.rs:46`](../../ui/dr-ui/src/collections_ui/controller.rs#L46), [`ui/dr-ui/src/collections_ui/drag.rs:274`](../../ui/dr-ui/src/collections_ui/drag.rs#L274), [`ui/dr-ui/src/collections_ui/mod.rs:1`](../../ui/dr-ui/src/collections_ui/mod.rs#L1), [`ui/dr-ui/src/collections_ui/press.rs:258`](../../ui/dr-ui/src/collections_ui/press.rs#L258), [`ui/dr-ui/src/collections_ui/press.rs:490`](../../ui/dr-ui/src/collections_ui/press.rs#L490), [`ui/dr-ui/src/collections_ui/press.rs:54`](../../ui/dr-ui/src/collections_ui/press.rs#L54), [`ui/dr-ui/src/collections_ui/rename_menu.rs:196`](../../ui/dr-ui/src/collections_ui/rename_menu.rs#L196), [`ui/dr-ui/src/collections_ui/rename_menu.rs:21`](../../ui/dr-ui/src/collections_ui/rename_menu.rs#L21), [`ui/dr-ui/src/collections_ui/tree_sync.rs:246`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L246), [`ui/dr-ui/src/collections_ui/tree_sync.rs:317`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L317), [`ui/dr-ui/src/collections_ui/tree_sync.rs:339`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L339), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:121`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L121), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:171`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L171), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:444`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L444), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:522`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L522), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:586`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L586), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:287`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L287), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:344`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L344), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:394`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L394), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:517`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L517), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:581`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L581), [`ui/dr-ui/src/derived_sync.rs:1`](../../ui/dr-ui/src/derived_sync.rs#L1), [`ui/dr-ui/src/library/spans.rs:139`](../../ui/dr-ui/src/library/spans.rs#L139), [`ui/dr-ui/src/library/spans.rs:58`](../../ui/dr-ui/src/library/spans.rs#L58), [`ui/dr-ui/src/library/spans.rs:84`](../../ui/dr-ui/src/library/spans.rs#L84), [`ui/dr-ui/src/library_ui/sync.rs:218`](../../ui/dr-ui/src/library_ui/sync.rs#L218), [`ui/dr-ui/src/library_ui/timeline.rs:513`](../../ui/dr-ui/src/library_ui/timeline.rs#L513), [`ui/dr-ui/src/library_ui/window.rs:273`](../../ui/dr-ui/src/library_ui/window.rs#L273), [`ui/dr-ui/ui/app.slint:2904`](../../ui/dr-ui/ui/app.slint#L2904), [`ui/dr-ui/ui/collections.slint:1182`](../../ui/dr-ui/ui/collections.slint#L1182), [`ui/dr-ui/ui/collections.slint:4`](../../ui/dr-ui/ui/collections.slint#L4), [`ui/dr-ui/ui/collections.slint:587`](../../ui/dr-ui/ui/collections.slint#L587), [`ui/dr-ui/ui/library.slint:1268`](../../ui/dr-ui/ui/library.slint#L1268), [`ui/dr-ui/ui/library.slint:1597`](../../ui/dr-ui/ui/library.slint#L1597), [`ui/dr-ui/ui/library.slint:3219`](../../ui/dr-ui/ui/library.slint#L3219), [`ui/dr-ui/ui/library.slint:4501`](../../ui/dr-ui/ui/library.slint#L4501), [`ui/dr-ui/ui/library.slint:4588`](../../ui/dr-ui/ui/library.slint#L4588), [`ui/dr-ui/ui/library.slint:482`](../../ui/dr-ui/ui/library.slint#L482), [`ui/dr-ui/ui/library.slint:507`](../../ui/dr-ui/ui/library.slint#L507), [`ui/dr-ui/ui/library.slint:549`](../../ui/dr-ui/ui/library.slint#L549), [`ui/dr-ui/ui/library.slint:559`](../../ui/dr-ui/ui/library.slint#L559) |
+| FR-CAT-8 | [`core/dr-catalog/src/schema.rs:740`](../../core/dr-catalog/src/schema.rs#L740), [`core/dr-pipeline/src/coverage.rs:1`](../../core/dr-pipeline/src/coverage.rs#L1), [`core/dr-pipeline/src/graph.rs:587`](../../core/dr-pipeline/src/graph.rs#L587), [`core/dr-pipeline/src/graph.rs:640`](../../core/dr-pipeline/src/graph.rs#L640), [`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:1400`](../../core/dr-pipeline/src/sidecar.rs#L1400), [`core/dr-pipeline/src/sidecar.rs:2232`](../../core/dr-pipeline/src/sidecar.rs#L2232), [`core/dr-pipeline/src/sidecar.rs:96`](../../core/dr-pipeline/src/sidecar.rs#L96), [`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:56`](../../core/dr-sync/src/scan.rs#L56), [`core/dr-sync/src/scan.rs:926`](../../core/dr-sync/src/scan.rs#L926), [`ui/dr-ui/src/develop/mask_ops.rs:1076`](../../ui/dr-ui/src/develop/mask_ops.rs#L1076), [`ui/dr-ui/src/develop/mask_ops.rs:1130`](../../ui/dr-ui/src/develop/mask_ops.rs#L1130), [`ui/dr-ui/src/develop/mask_ops.rs:178`](../../ui/dr-ui/src/develop/mask_ops.rs#L178), [`ui/dr-ui/src/develop/masks.rs:740`](../../ui/dr-ui/src/develop/masks.rs#L740), [`ui/dr-ui/src/develop/session.rs:561`](../../ui/dr-ui/src/develop/session.rs#L561), [`ui/dr-ui/src/develop/session.rs:590`](../../ui/dr-ui/src/develop/session.rs#L590), [`ui/dr-ui/src/export.rs:813`](../../ui/dr-ui/src/export.rs#L813), [`ui/dr-ui/src/lib.rs:1184`](../../ui/dr-ui/src/lib.rs#L1184), [`ui/dr-ui/src/lib.rs:1244`](../../ui/dr-ui/src/lib.rs#L1244), [`ui/dr-ui/src/lib.rs:2692`](../../ui/dr-ui/src/lib.rs#L2692), [`ui/dr-ui/src/lib.rs:2839`](../../ui/dr-ui/src/lib.rs#L2839), [`ui/dr-ui/src/lib.rs:759`](../../ui/dr-ui/src/lib.rs#L759), [`ui/dr-ui/src/library/scan.rs:226`](../../ui/dr-ui/src/library/scan.rs#L226), [`ui/dr-ui/src/library/scan.rs:261`](../../ui/dr-ui/src/library/scan.rs#L261), [`ui/dr-ui/src/library/scan.rs:34`](../../ui/dr-ui/src/library/scan.rs#L34), [`ui/dr-ui/src/library/sidecar.rs:100`](../../ui/dr-ui/src/library/sidecar.rs#L100), [`ui/dr-ui/src/library/sidecar.rs:11`](../../ui/dr-ui/src/library/sidecar.rs#L11), [`ui/dr-ui/src/library/sidecar.rs:373`](../../ui/dr-ui/src/library/sidecar.rs#L373), [`ui/dr-ui/src/library/sidecar.rs:63`](../../ui/dr-ui/src/library/sidecar.rs#L63), [`ui/dr-ui/src/library/thumbnails_fetch.rs:413`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L413), [`ui/dr-ui/src/library_ui/grid.rs:692`](../../ui/dr-ui/src/library_ui/grid.rs#L692), [`ui/dr-ui/src/library_ui/open.rs:455`](../../ui/dr-ui/src/library_ui/open.rs#L455), [`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:1182`](../../core/dr-catalog/src/schema.rs#L1182), [`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:35`](../../core/dr-sync-nextcloud/src/desktop_client.rs#L35), [`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:211`](../../core/dr-sync/src/scan.rs#L211), [`core/dr-sync/src/scan.rs:519`](../../core/dr-sync/src/scan.rs#L519), [`core/dr-types/src/lib.rs:122`](../../core/dr-types/src/lib.rs#L122), [`ui/dr-ui/src/develop/render.rs:584`](../../ui/dr-ui/src/develop/render.rs#L584), [`ui/dr-ui/src/develop/render.rs:627`](../../ui/dr-ui/src/develop/render.rs#L627), [`ui/dr-ui/src/library/filters.rs:84`](../../ui/dr-ui/src/library/filters.rs#L84), [`ui/dr-ui/src/library/scan.rs:126`](../../ui/dr-ui/src/library/scan.rs#L126), [`ui/dr-ui/src/library/scan.rs:179`](../../ui/dr-ui/src/library/scan.rs#L179), [`ui/dr-ui/src/library/scan.rs:210`](../../ui/dr-ui/src/library/scan.rs#L210), [`ui/dr-ui/src/library/scan.rs:261`](../../ui/dr-ui/src/library/scan.rs#L261), [`ui/dr-ui/src/library/scan.rs:605`](../../ui/dr-ui/src/library/scan.rs#L605), [`ui/dr-ui/src/library/sidecar.rs:100`](../../ui/dr-ui/src/library/sidecar.rs#L100), [`ui/dr-ui/src/library/sidecar.rs:357`](../../ui/dr-ui/src/library/sidecar.rs#L357), [`ui/dr-ui/src/library/sidecar.rs:373`](../../ui/dr-ui/src/library/sidecar.rs#L373), [`ui/dr-ui/src/library/sidecar.rs:427`](../../ui/dr-ui/src/library/sidecar.rs#L427), [`ui/dr-ui/src/library/spans.rs:361`](../../ui/dr-ui/src/library/spans.rs#L361), [`ui/dr-ui/src/library/thumbnails_fetch.rs:393`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L393), [`ui/dr-ui/src/library/thumbnails_fetch.rs:449`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L449), [`ui/dr-ui/src/library/thumbnails_gen.rs:74`](../../ui/dr-ui/src/library/thumbnails_gen.rs#L74), [`ui/dr-ui/src/library_ui/controller.rs:279`](../../ui/dr-ui/src/library_ui/controller.rs#L279), [`ui/dr-ui/src/library_ui/controller.rs:315`](../../ui/dr-ui/src/library_ui/controller.rs#L315), [`ui/dr-ui/src/library_ui/controller.rs:323`](../../ui/dr-ui/src/library_ui/controller.rs#L323), [`ui/dr-ui/src/library_ui/controller.rs:568`](../../ui/dr-ui/src/library_ui/controller.rs#L568), [`ui/dr-ui/src/library_ui/controller.rs:657`](../../ui/dr-ui/src/library_ui/controller.rs#L657), [`ui/dr-ui/src/library_ui/filter_bar.rs:405`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L405), [`ui/dr-ui/src/library_ui/filter_bar.rs:491`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L491), [`ui/dr-ui/src/library_ui/offline.rs:561`](../../ui/dr-ui/src/library_ui/offline.rs#L561), [`ui/dr-ui/src/library_ui/offline.rs:607`](../../ui/dr-ui/src/library_ui/offline.rs#L607), [`ui/dr-ui/src/library_ui/offline.rs:623`](../../ui/dr-ui/src/library_ui/offline.rs#L623), [`ui/dr-ui/src/library_ui/open.rs:524`](../../ui/dr-ui/src/library_ui/open.rs#L524), [`ui/dr-ui/src/library_ui/open.rs:604`](../../ui/dr-ui/src/library_ui/open.rs#L604), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:718`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L718), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:71`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L71), [`ui/dr-ui/src/library_ui/sync.rs:270`](../../ui/dr-ui/src/library_ui/sync.rs#L270), [`ui/dr-ui/src/library_ui/sync.rs:397`](../../ui/dr-ui/src/library_ui/sync.rs#L397), [`ui/dr-ui/src/library_ui/sync.rs:80`](../../ui/dr-ui/src/library_ui/sync.rs#L80), [`ui/dr-ui/src/library_ui/window.rs:551`](../../ui/dr-ui/src/library_ui/window.rs#L551), [`ui/dr-ui/src/library_ui/window.rs:831`](../../ui/dr-ui/src/library_ui/window.rs#L831), [`ui/dr-ui/src/presets.rs:486`](../../ui/dr-ui/src/presets.rs#L486), [`ui/dr-ui/src/presets.rs:498`](../../ui/dr-ui/src/presets.rs#L498), [`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:1011`](../../core/dr-catalog/src/schema.rs#L1011), [`core/dr-catalog/src/schema.rs:603`](../../core/dr-catalog/src/schema.rs#L603), [`core/dr-catalog/src/schema.rs:781`](../../core/dr-catalog/src/schema.rs#L781), [`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-face/src/references.rs:1`](../../core/dr-face/src/references.rs#L1), [`core/dr-types/src/settings.rs:129`](../../core/dr-types/src/settings.rs#L129), [`ui/dr-ui/src/develop/segmentation.rs:104`](../../ui/dr-ui/src/develop/segmentation.rs#L104), [`ui/dr-ui/src/develop/segmentation.rs:170`](../../ui/dr-ui/src/develop/segmentation.rs#L170), [`ui/dr-ui/src/develop/segmentation.rs:590`](../../ui/dr-ui/src/develop/segmentation.rs#L590), [`ui/dr-ui/src/develop/segmentation.rs:95`](../../ui/dr-ui/src/develop/segmentation.rs#L95), [`ui/dr-ui/src/develop/session.rs:23`](../../ui/dr-ui/src/develop/session.rs#L23), [`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:1434`](../../ui/dr-ui/src/identity_ui.rs#L1434), [`ui/dr-ui/src/identity_ui.rs:1`](../../ui/dr-ui/src/identity_ui.rs#L1), [`ui/dr-ui/src/lib.rs:2810`](../../ui/dr-ui/src/lib.rs#L2810), [`ui/dr-ui/src/repairs.rs:1`](../../ui/dr-ui/src/repairs.rs#L1), [`ui/dr-ui/ui/identity.slint:1`](../../ui/dr-ui/ui/identity.slint#L1), [`ui/dr-ui/ui/settings.slint:529`](../../ui/dr-ui/ui/settings.slint#L529), [`ui/dr-ui/ui/settings.slint:94`](../../ui/dr-ui/ui/settings.slint#L94) |
+| FR-CULL-10 | [`core/dr-catalog/src/faces.rs:1`](../../core/dr-catalog/src/faces.rs#L1), [`core/dr-catalog/src/schema.rs:1011`](../../core/dr-catalog/src/schema.rs#L1011), [`core/dr-catalog/src/schema.rs:603`](../../core/dr-catalog/src/schema.rs#L603), [`core/dr-catalog/src/schema.rs:781`](../../core/dr-catalog/src/schema.rs#L781), [`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-face/src/references.rs:1`](../../core/dr-face/src/references.rs#L1), [`core/dr-types/src/settings.rs:129`](../../core/dr-types/src/settings.rs#L129), [`ui/dr-ui/src/develop/segmentation.rs:104`](../../ui/dr-ui/src/develop/segmentation.rs#L104), [`ui/dr-ui/src/develop/segmentation.rs:170`](../../ui/dr-ui/src/develop/segmentation.rs#L170), [`ui/dr-ui/src/develop/segmentation.rs:590`](../../ui/dr-ui/src/develop/segmentation.rs#L590), [`ui/dr-ui/src/develop/segmentation.rs:95`](../../ui/dr-ui/src/develop/segmentation.rs#L95), [`ui/dr-ui/src/develop/session.rs:23`](../../ui/dr-ui/src/develop/session.rs#L23), [`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:1434`](../../ui/dr-ui/src/identity_ui.rs#L1434), [`ui/dr-ui/src/identity_ui.rs:1`](../../ui/dr-ui/src/identity_ui.rs#L1), [`ui/dr-ui/src/lib.rs:2811`](../../ui/dr-ui/src/lib.rs#L2811), [`ui/dr-ui/src/repairs.rs:1`](../../ui/dr-ui/src/repairs.rs#L1), [`ui/dr-ui/ui/identity.slint:1`](../../ui/dr-ui/ui/identity.slint#L1), [`ui/dr-ui/ui/settings.slint:529`](../../ui/dr-ui/ui/settings.slint#L529), [`ui/dr-ui/ui/settings.slint:94`](../../ui/dr-ui/ui/settings.slint#L94) |
| FR-CULL-11 | [`core/dr-catalog/src/faces.rs:1`](../../core/dr-catalog/src/faces.rs#L1), [`core/dr-catalog/src/schema.rs:1011`](../../core/dr-catalog/src/schema.rs#L1011), [`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/filters.rs:105`](../../ui/dr-ui/src/library/filters.rs#L105), [`ui/dr-ui/src/library/filters.rs:155`](../../ui/dr-ui/src/library/filters.rs#L155), [`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:1011`](../../core/dr-catalog/src/schema.rs#L1011), [`core/dr-catalog/src/schema.rs:603`](../../core/dr-catalog/src/schema.rs#L603), [`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-13 | [`core/dr-catalog/src/schema.rs:917`](../../core/dr-catalog/src/schema.rs#L917), [`core/dr-types/src/place.rs:129`](../../core/dr-types/src/place.rs#L129), [`ui/dr-ui/src/identity.rs:104`](../../ui/dr-ui/src/identity.rs#L104), [`ui/dr-ui/src/library/filters.rs:131`](../../ui/dr-ui/src/library/filters.rs#L131), [`ui/dr-ui/src/library/filters.rs:683`](../../ui/dr-ui/src/library/filters.rs#L683), [`ui/dr-ui/src/library/filters.rs:726`](../../ui/dr-ui/src/library/filters.rs#L726), [`ui/dr-ui/src/library/filters.rs:764`](../../ui/dr-ui/src/library/filters.rs#L764), [`ui/dr-ui/ui/app.slint:665`](../../ui/dr-ui/ui/app.slint#L665), [`ui/dr-ui/ui/identity.slint:63`](../../ui/dr-ui/ui/identity.slint#L63), [`ui/dr-ui/ui/library.slint:1512`](../../ui/dr-ui/ui/library.slint#L1512) |
+| FR-CULL-13 | [`core/dr-catalog/src/schema.rs:917`](../../core/dr-catalog/src/schema.rs#L917), [`core/dr-types/src/place.rs:129`](../../core/dr-types/src/place.rs#L129), [`ui/dr-ui/src/identity.rs:104`](../../ui/dr-ui/src/identity.rs#L104), [`ui/dr-ui/src/library/filters.rs:131`](../../ui/dr-ui/src/library/filters.rs#L131), [`ui/dr-ui/src/library/filters.rs:683`](../../ui/dr-ui/src/library/filters.rs#L683), [`ui/dr-ui/src/library/filters.rs:726`](../../ui/dr-ui/src/library/filters.rs#L726), [`ui/dr-ui/src/library/filters.rs:764`](../../ui/dr-ui/src/library/filters.rs#L764), [`ui/dr-ui/ui/identity.slint:63`](../../ui/dr-ui/ui/identity.slint#L63), [`ui/dr-ui/ui/library.slint:1782`](../../ui/dr-ui/ui/library.slint#L1782), [`ui/dr-ui/ui/library.slint:686`](../../ui/dr-ui/ui/library.slint#L686) |
| 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/render.rs:1203`](../../ui/dr-ui/src/develop/render.rs#L1203), [`ui/dr-ui/src/develop/render.rs:1267`](../../ui/dr-ui/src/develop/render.rs#L1267), [`ui/dr-ui/src/develop/render.rs:1290`](../../ui/dr-ui/src/develop/render.rs#L1290), [`ui/dr-ui/src/develop/render.rs:256`](../../ui/dr-ui/src/develop/render.rs#L256), [`ui/dr-ui/src/develop/render.rs:269`](../../ui/dr-ui/src/develop/render.rs#L269), [`ui/dr-ui/src/develop/render.rs:314`](../../ui/dr-ui/src/develop/render.rs#L314), [`ui/dr-ui/src/develop/render.rs:325`](../../ui/dr-ui/src/develop/render.rs#L325), [`ui/dr-ui/src/develop/render.rs:331`](../../ui/dr-ui/src/develop/render.rs#L331), [`ui/dr-ui/src/develop/render.rs:348`](../../ui/dr-ui/src/develop/render.rs#L348), [`ui/dr-ui/src/develop/session.rs:118`](../../ui/dr-ui/src/develop/session.rs#L118), [`ui/dr-ui/src/develop/session.rs:138`](../../ui/dr-ui/src/develop/session.rs#L138), [`ui/dr-ui/src/develop/session.rs:144`](../../ui/dr-ui/src/develop/session.rs#L144), [`ui/dr-ui/src/develop_ui.rs:1199`](../../ui/dr-ui/src/develop_ui.rs#L1199), [`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:1272`](../../ui/dr-ui/src/lib.rs#L1272), [`ui/dr-ui/src/lib.rs:2211`](../../ui/dr-ui/src/lib.rs#L2211), [`ui/dr-ui/src/lib.rs:2324`](../../ui/dr-ui/src/lib.rs#L2324), [`ui/dr-ui/src/lib.rs:2365`](../../ui/dr-ui/src/lib.rs#L2365), [`ui/dr-ui/src/lib.rs:443`](../../ui/dr-ui/src/lib.rs#L443), [`ui/dr-ui/src/peaking.rs:1`](../../ui/dr-ui/src/peaking.rs#L1), [`ui/dr-ui/ui/app.slint:130`](../../ui/dr-ui/ui/app.slint#L130), [`ui/dr-ui/ui/app.slint:1984`](../../ui/dr-ui/ui/app.slint#L1984), [`ui/dr-ui/ui/app.slint:2991`](../../ui/dr-ui/ui/app.slint#L2991), [`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:171`](../../core/dr-pipeline/src/sidecar.rs#L171), [`core/dr-xmp/src/lib.rs:442`](../../core/dr-xmp/src/lib.rs#L442), [`ui/dr-ui/src/library/filters.rs:64`](../../ui/dr-ui/src/library/filters.rs#L64), [`ui/dr-ui/src/library/sidecar.rs:11`](../../ui/dr-ui/src/library/sidecar.rs#L11) |
-| FR-CULL-5 | [`core/dr-catalog/src/bursts.rs:1`](../../core/dr-catalog/src/bursts.rs#L1), [`core/dr-catalog/src/schema.rs:646`](../../core/dr-catalog/src/schema.rs#L646), [`ui/dr-ui/src/bursts.rs:1`](../../ui/dr-ui/src/bursts.rs#L1), [`ui/dr-ui/src/library/cells.rs:19`](../../ui/dr-ui/src/library/cells.rs#L19), [`ui/dr-ui/src/library/cells.rs:769`](../../ui/dr-ui/src/library/cells.rs#L769) |
-| 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:1011`](../../core/dr-catalog/src/schema.rs#L1011), [`core/dr-catalog/src/schema.rs:714`](../../core/dr-catalog/src/schema.rs#L714), [`core/dr-catalog/src/schema.rs:970`](../../core/dr-catalog/src/schema.rs#L970), [`core/dr-face/src/align.rs:296`](../../core/dr-face/src/align.rs#L296), [`core/dr-types/src/settings.rs:176`](../../core/dr-types/src/settings.rs#L176), [`ui/dr-ui/examples/face_detectors.rs:1`](../../ui/dr-ui/examples/face_detectors.rs#L1), [`ui/dr-ui/examples/face_native.rs:1`](../../ui/dr-ui/examples/face_native.rs#L1), [`ui/dr-ui/src/derived_sync.rs:124`](../../ui/dr-ui/src/derived_sync.rs#L124), [`ui/dr-ui/src/faces.rs:1`](../../ui/dr-ui/src/faces.rs#L1), [`ui/dr-ui/src/faces.rs:446`](../../ui/dr-ui/src/faces.rs#L446), [`ui/dr-ui/src/faces.rs:462`](../../ui/dr-ui/src/faces.rs#L462), [`ui/dr-ui/src/faces.rs:584`](../../ui/dr-ui/src/faces.rs#L584), [`ui/dr-ui/src/identity_ui.rs:1434`](../../ui/dr-ui/src/identity_ui.rs#L1434), [`ui/dr-ui/src/identity_ui.rs:617`](../../ui/dr-ui/src/identity_ui.rs#L617), [`ui/dr-ui/src/lib.rs:1739`](../../ui/dr-ui/src/lib.rs#L1739), [`ui/dr-ui/src/lib.rs:3098`](../../ui/dr-ui/src/lib.rs#L3098), [`ui/dr-ui/src/library/sweep.rs:241`](../../ui/dr-ui/src/library/sweep.rs#L241), [`ui/dr-ui/src/library/sweep.rs:506`](../../ui/dr-ui/src/library/sweep.rs#L506), [`ui/dr-ui/src/library_ui/controller.rs:401`](../../ui/dr-ui/src/library_ui/controller.rs#L401), [`ui/dr-ui/src/library_ui/controller.rs:488`](../../ui/dr-ui/src/library_ui/controller.rs#L488), [`ui/dr-ui/src/repairs.rs:1`](../../ui/dr-ui/src/repairs.rs#L1), [`ui/dr-ui/src/settings_ui.rs:210`](../../ui/dr-ui/src/settings_ui.rs#L210), [`ui/dr-ui/src/settings_ui.rs:571`](../../ui/dr-ui/src/settings_ui.rs#L571), [`ui/dr-ui/ui/app.slint:902`](../../ui/dr-ui/ui/app.slint#L902), [`ui/dr-ui/ui/settings.slint:100`](../../ui/dr-ui/ui/settings.slint#L100), [`ui/dr-ui/ui/settings.slint:467`](../../ui/dr-ui/ui/settings.slint#L467), [`ui/dr-ui/ui/settings.slint:529`](../../ui/dr-ui/ui/settings.slint#L529), [`ui/dr-ui/ui/settings.slint:82`](../../ui/dr-ui/ui/settings.slint#L82), [`ui/dr-ui/ui/settings.slint:94`](../../ui/dr-ui/ui/settings.slint#L94) |
-| FR-CULL-8a | [`core/dr-catalog/src/faces.rs:124`](../../core/dr-catalog/src/faces.rs#L124), [`core/dr-catalog/src/schema.rs:917`](../../core/dr-catalog/src/schema.rs#L917), [`core/dr-face/src/classify.rs:1`](../../core/dr-face/src/classify.rs#L1), [`core/dr-face/src/eyes.rs:1`](../../core/dr-face/src/eyes.rs#L1), [`core/dr-face/src/landmarks.rs:1`](../../core/dr-face/src/landmarks.rs#L1), [`core/dr-types/src/place.rs:129`](../../core/dr-types/src/place.rs#L129), [`ui/dr-ui/src/faces.rs:166`](../../ui/dr-ui/src/faces.rs#L166), [`ui/dr-ui/src/faces.rs:1821`](../../ui/dr-ui/src/faces.rs#L1821), [`ui/dr-ui/src/faces.rs:308`](../../ui/dr-ui/src/faces.rs#L308), [`ui/dr-ui/src/identity.rs:104`](../../ui/dr-ui/src/identity.rs#L104), [`ui/dr-ui/src/library/filters.rs:131`](../../ui/dr-ui/src/library/filters.rs#L131), [`ui/dr-ui/src/library/filters.rs:683`](../../ui/dr-ui/src/library/filters.rs#L683), [`ui/dr-ui/src/library/filters.rs:726`](../../ui/dr-ui/src/library/filters.rs#L726), [`ui/dr-ui/src/library/filters.rs:764`](../../ui/dr-ui/src/library/filters.rs#L764), [`ui/dr-ui/src/repairs.rs:571`](../../ui/dr-ui/src/repairs.rs#L571), [`ui/dr-ui/ui/app.slint:665`](../../ui/dr-ui/ui/app.slint#L665), [`ui/dr-ui/ui/identity.slint:273`](../../ui/dr-ui/ui/identity.slint#L273), [`ui/dr-ui/ui/identity.slint:63`](../../ui/dr-ui/ui/identity.slint#L63), [`ui/dr-ui/ui/library.slint:1512`](../../ui/dr-ui/ui/library.slint#L1512) |
+| 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/render.rs:1203`](../../ui/dr-ui/src/develop/render.rs#L1203), [`ui/dr-ui/src/develop/render.rs:1267`](../../ui/dr-ui/src/develop/render.rs#L1267), [`ui/dr-ui/src/develop/render.rs:1290`](../../ui/dr-ui/src/develop/render.rs#L1290), [`ui/dr-ui/src/develop/render.rs:256`](../../ui/dr-ui/src/develop/render.rs#L256), [`ui/dr-ui/src/develop/render.rs:269`](../../ui/dr-ui/src/develop/render.rs#L269), [`ui/dr-ui/src/develop/render.rs:314`](../../ui/dr-ui/src/develop/render.rs#L314), [`ui/dr-ui/src/develop/render.rs:325`](../../ui/dr-ui/src/develop/render.rs#L325), [`ui/dr-ui/src/develop/render.rs:331`](../../ui/dr-ui/src/develop/render.rs#L331), [`ui/dr-ui/src/develop/render.rs:348`](../../ui/dr-ui/src/develop/render.rs#L348), [`ui/dr-ui/src/develop/session.rs:118`](../../ui/dr-ui/src/develop/session.rs#L118), [`ui/dr-ui/src/develop/session.rs:138`](../../ui/dr-ui/src/develop/session.rs#L138), [`ui/dr-ui/src/develop/session.rs:144`](../../ui/dr-ui/src/develop/session.rs#L144), [`ui/dr-ui/src/develop_ui.rs:1207`](../../ui/dr-ui/src/develop_ui.rs#L1207), [`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:1273`](../../ui/dr-ui/src/lib.rs#L1273), [`ui/dr-ui/src/lib.rs:2212`](../../ui/dr-ui/src/lib.rs#L2212), [`ui/dr-ui/src/lib.rs:2325`](../../ui/dr-ui/src/lib.rs#L2325), [`ui/dr-ui/src/lib.rs:2366`](../../ui/dr-ui/src/lib.rs#L2366), [`ui/dr-ui/src/lib.rs:444`](../../ui/dr-ui/src/lib.rs#L444), [`ui/dr-ui/src/peaking.rs:1`](../../ui/dr-ui/src/peaking.rs#L1), [`ui/dr-ui/ui/app.slint:131`](../../ui/dr-ui/ui/app.slint#L131), [`ui/dr-ui/ui/app.slint:1720`](../../ui/dr-ui/ui/app.slint#L1720), [`ui/dr-ui/ui/app.slint:2726`](../../ui/dr-ui/ui/app.slint#L2726), [`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:171`](../../core/dr-pipeline/src/sidecar.rs#L171), [`core/dr-xmp/src/lib.rs:442`](../../core/dr-xmp/src/lib.rs#L442), [`ui/dr-ui/src/library/filters.rs:64`](../../ui/dr-ui/src/library/filters.rs#L64), [`ui/dr-ui/src/library/sidecar.rs:11`](../../ui/dr-ui/src/library/sidecar.rs#L11), [`ui/dr-ui/ui/library.slint:482`](../../ui/dr-ui/ui/library.slint#L482) |
+| FR-CULL-5 | [`core/dr-catalog/src/bursts.rs:1`](../../core/dr-catalog/src/bursts.rs#L1), [`core/dr-catalog/src/schema.rs:646`](../../core/dr-catalog/src/schema.rs#L646), [`ui/dr-ui/src/bursts.rs:1`](../../ui/dr-ui/src/bursts.rs#L1), [`ui/dr-ui/src/library/cells.rs:19`](../../ui/dr-ui/src/library/cells.rs#L19), [`ui/dr-ui/src/library/cells.rs:769`](../../ui/dr-ui/src/library/cells.rs#L769), [`ui/dr-ui/ui/library.slint:482`](../../ui/dr-ui/ui/library.slint#L482) |
+| 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:1011`](../../core/dr-catalog/src/schema.rs#L1011), [`core/dr-catalog/src/schema.rs:714`](../../core/dr-catalog/src/schema.rs#L714), [`core/dr-catalog/src/schema.rs:970`](../../core/dr-catalog/src/schema.rs#L970), [`core/dr-face/src/align.rs:296`](../../core/dr-face/src/align.rs#L296), [`core/dr-types/src/settings.rs:176`](../../core/dr-types/src/settings.rs#L176), [`ui/dr-ui/examples/face_detectors.rs:1`](../../ui/dr-ui/examples/face_detectors.rs#L1), [`ui/dr-ui/examples/face_native.rs:1`](../../ui/dr-ui/examples/face_native.rs#L1), [`ui/dr-ui/src/derived_sync.rs:124`](../../ui/dr-ui/src/derived_sync.rs#L124), [`ui/dr-ui/src/faces.rs:1`](../../ui/dr-ui/src/faces.rs#L1), [`ui/dr-ui/src/faces.rs:446`](../../ui/dr-ui/src/faces.rs#L446), [`ui/dr-ui/src/faces.rs:462`](../../ui/dr-ui/src/faces.rs#L462), [`ui/dr-ui/src/faces.rs:584`](../../ui/dr-ui/src/faces.rs#L584), [`ui/dr-ui/src/identity_ui.rs:1434`](../../ui/dr-ui/src/identity_ui.rs#L1434), [`ui/dr-ui/src/identity_ui.rs:617`](../../ui/dr-ui/src/identity_ui.rs#L617), [`ui/dr-ui/src/lib.rs:1740`](../../ui/dr-ui/src/lib.rs#L1740), [`ui/dr-ui/src/lib.rs:3099`](../../ui/dr-ui/src/lib.rs#L3099), [`ui/dr-ui/src/library/sweep.rs:241`](../../ui/dr-ui/src/library/sweep.rs#L241), [`ui/dr-ui/src/library/sweep.rs:506`](../../ui/dr-ui/src/library/sweep.rs#L506), [`ui/dr-ui/src/library_ui/controller.rs:401`](../../ui/dr-ui/src/library_ui/controller.rs#L401), [`ui/dr-ui/src/library_ui/controller.rs:488`](../../ui/dr-ui/src/library_ui/controller.rs#L488), [`ui/dr-ui/src/repairs.rs:1`](../../ui/dr-ui/src/repairs.rs#L1), [`ui/dr-ui/src/settings_ui.rs:210`](../../ui/dr-ui/src/settings_ui.rs#L210), [`ui/dr-ui/src/settings_ui.rs:571`](../../ui/dr-ui/src/settings_ui.rs#L571), [`ui/dr-ui/ui/app.slint:645`](../../ui/dr-ui/ui/app.slint#L645), [`ui/dr-ui/ui/settings.slint:100`](../../ui/dr-ui/ui/settings.slint#L100), [`ui/dr-ui/ui/settings.slint:467`](../../ui/dr-ui/ui/settings.slint#L467), [`ui/dr-ui/ui/settings.slint:529`](../../ui/dr-ui/ui/settings.slint#L529), [`ui/dr-ui/ui/settings.slint:82`](../../ui/dr-ui/ui/settings.slint#L82), [`ui/dr-ui/ui/settings.slint:94`](../../ui/dr-ui/ui/settings.slint#L94) |
+| FR-CULL-8a | [`core/dr-catalog/src/faces.rs:124`](../../core/dr-catalog/src/faces.rs#L124), [`core/dr-catalog/src/schema.rs:917`](../../core/dr-catalog/src/schema.rs#L917), [`core/dr-face/src/classify.rs:1`](../../core/dr-face/src/classify.rs#L1), [`core/dr-face/src/eyes.rs:1`](../../core/dr-face/src/eyes.rs#L1), [`core/dr-face/src/landmarks.rs:1`](../../core/dr-face/src/landmarks.rs#L1), [`core/dr-types/src/place.rs:129`](../../core/dr-types/src/place.rs#L129), [`ui/dr-ui/src/faces.rs:166`](../../ui/dr-ui/src/faces.rs#L166), [`ui/dr-ui/src/faces.rs:1821`](../../ui/dr-ui/src/faces.rs#L1821), [`ui/dr-ui/src/faces.rs:308`](../../ui/dr-ui/src/faces.rs#L308), [`ui/dr-ui/src/identity.rs:104`](../../ui/dr-ui/src/identity.rs#L104), [`ui/dr-ui/src/library/filters.rs:131`](../../ui/dr-ui/src/library/filters.rs#L131), [`ui/dr-ui/src/library/filters.rs:683`](../../ui/dr-ui/src/library/filters.rs#L683), [`ui/dr-ui/src/library/filters.rs:726`](../../ui/dr-ui/src/library/filters.rs#L726), [`ui/dr-ui/src/library/filters.rs:764`](../../ui/dr-ui/src/library/filters.rs#L764), [`ui/dr-ui/src/repairs.rs:571`](../../ui/dr-ui/src/repairs.rs#L571), [`ui/dr-ui/ui/identity.slint:273`](../../ui/dr-ui/ui/identity.slint#L273), [`ui/dr-ui/ui/identity.slint:63`](../../ui/dr-ui/ui/identity.slint#L63), [`ui/dr-ui/ui/library.slint:1782`](../../ui/dr-ui/ui/library.slint#L1782), [`ui/dr-ui/ui/library.slint:686`](../../ui/dr-ui/ui/library.slint#L686) |
| FR-CULL-9 | [`core/dr-catalog/src/faces.rs:1`](../../core/dr-catalog/src/faces.rs#L1), [`core/dr-catalog/src/schema.rs:1011`](../../core/dr-catalog/src/schema.rs#L1011), [`core/dr-catalog/src/schema.rs:781`](../../core/dr-catalog/src/schema.rs#L781), [`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:129`](../../core/dr-types/src/settings.rs#L129), [`ui/dr-ui/src/faces.rs:1`](../../ui/dr-ui/src/faces.rs#L1), [`ui/dr-ui/src/faces.rs:584`](../../ui/dr-ui/src/faces.rs#L584), [`ui/dr-ui/src/identity_ui.rs:1`](../../ui/dr-ui/src/identity_ui.rs#L1), [`ui/dr-ui/src/repairs.rs:517`](../../ui/dr-ui/src/repairs.rs#L517), [`ui/dr-ui/ui/identity.slint:347`](../../ui/dr-ui/ui/identity.slint#L347) |
| 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:1027`](../../core/dr-gpu/src/mask.rs#L1027), [`core/dr-gpu/src/mask.rs:1251`](../../core/dr-gpu/src/mask.rs#L1251), [`core/dr-gpu/src/mask.rs:1509`](../../core/dr-gpu/src/mask.rs#L1509), [`core/dr-gpu/src/mask.rs:421`](../../core/dr-gpu/src/mask.rs#L421), [`core/dr-gpu/src/mask.rs:463`](../../core/dr-gpu/src/mask.rs#L463), [`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:834`](../../core/dr-gpu/src/mask.rs#L834), [`core/dr-gpu/src/mask.rs:85`](../../core/dr-gpu/src/mask.rs#L85), [`core/dr-gpu/src/mask.rs:913`](../../core/dr-gpu/src/mask.rs#L913), [`core/dr-gpu/src/shaders/mask.wgsl:117`](../../core/dr-gpu/src/shaders/mask.wgsl#L117), [`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:2845`](../../core/dr-pipeline/src/mask.rs#L2845), [`core/dr-pipeline/src/mask.rs:2858`](../../core/dr-pipeline/src/mask.rs#L2858), [`core/dr-pipeline/src/mask.rs:2877`](../../core/dr-pipeline/src/mask.rs#L2877), [`core/dr-pipeline/src/mask.rs:2891`](../../core/dr-pipeline/src/mask.rs#L2891), [`core/dr-pipeline/src/mask.rs:2901`](../../core/dr-pipeline/src/mask.rs#L2901), [`core/dr-pipeline/src/mask.rs:710`](../../core/dr-pipeline/src/mask.rs#L710), [`core/dr-pipeline/src/mask.rs:749`](../../core/dr-pipeline/src/mask.rs#L749), [`core/dr-pipeline/src/mask.rs:809`](../../core/dr-pipeline/src/mask.rs#L809), [`core/dr-pipeline/src/mask.rs:828`](../../core/dr-pipeline/src/mask.rs#L828), [`core/dr-pipeline/src/mask.rs:852`](../../core/dr-pipeline/src/mask.rs#L852), [`core/dr-pipeline/src/mask.rs:864`](../../core/dr-pipeline/src/mask.rs#L864), [`core/dr-pipeline/src/mask.rs:876`](../../core/dr-pipeline/src/mask.rs#L876), [`core/dr-pipeline/src/sidecar.rs:1336`](../../core/dr-pipeline/src/sidecar.rs#L1336), [`core/dr-pipeline/src/sidecar.rs:1515`](../../core/dr-pipeline/src/sidecar.rs#L1515), [`core/dr-pipeline/src/sidecar.rs:1604`](../../core/dr-pipeline/src/sidecar.rs#L1604), [`core/dr-pipeline/src/sidecar.rs:1708`](../../core/dr-pipeline/src/sidecar.rs#L1708), [`core/dr-pipeline/src/sidecar.rs:1916`](../../core/dr-pipeline/src/sidecar.rs#L1916), [`core/dr-pipeline/tests/mask_sidecar.rs:1157`](../../core/dr-pipeline/tests/mask_sidecar.rs#L1157), [`core/dr-pipeline/tests/mask_sidecar.rs:1186`](../../core/dr-pipeline/tests/mask_sidecar.rs#L1186), [`core/dr-pipeline/tests/mask_sidecar.rs:1204`](../../core/dr-pipeline/tests/mask_sidecar.rs#L1204), [`core/dr-pipeline/tests/mask_sidecar.rs:1234`](../../core/dr-pipeline/tests/mask_sidecar.rs#L1234), [`ui/dr-ui/src/develop/mask_ops.rs:341`](../../ui/dr-ui/src/develop/mask_ops.rs#L341), [`ui/dr-ui/src/develop/mask_ops.rs:638`](../../ui/dr-ui/src/develop/mask_ops.rs#L638), [`ui/dr-ui/src/develop/mask_ops.rs:665`](../../ui/dr-ui/src/develop/mask_ops.rs#L665), [`ui/dr-ui/src/develop/mask_ops.rs:697`](../../ui/dr-ui/src/develop/mask_ops.rs#L697), [`ui/dr-ui/src/develop/mask_ops.rs:721`](../../ui/dr-ui/src/develop/mask_ops.rs#L721), [`ui/dr-ui/src/develop/mask_ops.rs:727`](../../ui/dr-ui/src/develop/mask_ops.rs#L727), [`ui/dr-ui/src/develop/mask_ops.rs:734`](../../ui/dr-ui/src/develop/mask_ops.rs#L734), [`ui/dr-ui/src/develop/mask_ops.rs:754`](../../ui/dr-ui/src/develop/mask_ops.rs#L754), [`ui/dr-ui/src/labels.rs:63`](../../ui/dr-ui/src/labels.rs#L63), [`ui/dr-ui/src/masks_ui.rs:1216`](../../ui/dr-ui/src/masks_ui.rs#L1216), [`ui/dr-ui/src/masks_ui.rs:797`](../../ui/dr-ui/src/masks_ui.rs#L797) |
| FR-DEV-12 | [`core/dr-pipeline/ops/colour_grading.yaml:1`](../../core/dr-pipeline/ops/colour_grading.yaml#L1) |
-| FR-DEV-16 | [`ui/dr-ui/src/lib.rs:425`](../../ui/dr-ui/src/lib.rs#L425), [`ui/dr-ui/src/masks_ui.rs:713`](../../ui/dr-ui/src/masks_ui.rs#L713), [`ui/dr-ui/ui/adjust.slint:998`](../../ui/dr-ui/ui/adjust.slint#L998), [`ui/dr-ui/ui/app.slint:2576`](../../ui/dr-ui/ui/app.slint#L2576), [`ui/dr-ui/ui/app.slint:2589`](../../ui/dr-ui/ui/app.slint#L2589), [`ui/dr-ui/ui/masks.slint:832`](../../ui/dr-ui/ui/masks.slint#L832) |
+| FR-DEV-16 | [`ui/dr-ui/src/lib.rs:426`](../../ui/dr-ui/src/lib.rs#L426), [`ui/dr-ui/src/masks_ui.rs:713`](../../ui/dr-ui/src/masks_ui.rs#L713), [`ui/dr-ui/ui/adjust.slint:998`](../../ui/dr-ui/ui/adjust.slint#L998), [`ui/dr-ui/ui/app.slint:2311`](../../ui/dr-ui/ui/app.slint#L2311), [`ui/dr-ui/ui/app.slint:2324`](../../ui/dr-ui/ui/app.slint#L2324), [`ui/dr-ui/ui/masks.slint:832`](../../ui/dr-ui/ui/masks.slint#L832) |
| 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-19 | [`core/dr-pipeline/src/mask.rs:1307`](../../core/dr-pipeline/src/mask.rs#L1307) |
| FR-DEV-19a | [`core/dr-gpu/src/mask.rs:761`](../../core/dr-gpu/src/mask.rs#L761), [`core/dr-pipeline/src/mask.rs:1588`](../../core/dr-pipeline/src/mask.rs#L1588), [`core/dr-pipeline/src/mask.rs:2919`](../../core/dr-pipeline/src/mask.rs#L2919), [`core/dr-pipeline/src/mask.rs:988`](../../core/dr-pipeline/src/mask.rs#L988), [`core/dr-pipeline/src/sidecar.rs:1226`](../../core/dr-pipeline/src/sidecar.rs#L1226), [`core/dr-pipeline/tests/mask_sidecar.rs:1347`](../../core/dr-pipeline/tests/mask_sidecar.rs#L1347), [`core/dr-pipeline/tests/mask_sidecar.rs:1373`](../../core/dr-pipeline/tests/mask_sidecar.rs#L1373), [`ui/dr-ui/src/develop/masks.rs:431`](../../ui/dr-ui/src/develop/masks.rs#L431), [`ui/dr-ui/src/develop/masks.rs:492`](../../ui/dr-ui/src/develop/masks.rs#L492), [`ui/dr-ui/src/develop/masks.rs:511`](../../ui/dr-ui/src/develop/masks.rs#L511), [`ui/dr-ui/src/develop/session.rs:188`](../../ui/dr-ui/src/develop/session.rs#L188), [`ui/dr-ui/src/labels.rs:73`](../../ui/dr-ui/src/labels.rs#L73), [`ui/dr-ui/src/masks_ui.rs:1083`](../../ui/dr-ui/src/masks_ui.rs#L1083), [`ui/dr-ui/src/masks_ui.rs:1155`](../../ui/dr-ui/src/masks_ui.rs#L1155), [`ui/dr-ui/src/masks_ui.rs:1514`](../../ui/dr-ui/src/masks_ui.rs#L1514), [`ui/dr-ui/src/masks_ui.rs:270`](../../ui/dr-ui/src/masks_ui.rs#L270), [`ui/dr-ui/ui/masks.slint:150`](../../ui/dr-ui/ui/masks.slint#L150), [`ui/dr-ui/ui/masks.slint:175`](../../ui/dr-ui/ui/masks.slint#L175), [`ui/dr-ui/ui/masks.slint:337`](../../ui/dr-ui/ui/masks.slint#L337), [`ui/dr-ui/ui/masks.slint:406`](../../ui/dr-ui/ui/masks.slint#L406), [`ui/dr-ui/ui/masks.slint:770`](../../ui/dr-ui/ui/masks.slint#L770), [`ui/dr-ui/ui/masks.slint:855`](../../ui/dr-ui/ui/masks.slint#L855) |
-| FR-DEV-19b | [`ui/dr-ui/src/develop/mask_ops.rs:606`](../../ui/dr-ui/src/develop/mask_ops.rs#L606), [`ui/dr-ui/src/develop/masks.rs:592`](../../ui/dr-ui/src/develop/masks.rs#L592), [`ui/dr-ui/src/develop/session.rs:197`](../../ui/dr-ui/src/develop/session.rs#L197), [`ui/dr-ui/src/develop/session.rs:204`](../../ui/dr-ui/src/develop/session.rs#L204), [`ui/dr-ui/src/labels.rs:67`](../../ui/dr-ui/src/labels.rs#L67), [`ui/dr-ui/src/masks_ui.rs:1188`](../../ui/dr-ui/src/masks_ui.rs#L1188), [`ui/dr-ui/src/masks_ui.rs:1407`](../../ui/dr-ui/src/masks_ui.rs#L1407), [`ui/dr-ui/src/masks_ui.rs:1435`](../../ui/dr-ui/src/masks_ui.rs#L1435), [`ui/dr-ui/src/masks_ui.rs:1778`](../../ui/dr-ui/src/masks_ui.rs#L1778), [`ui/dr-ui/src/masks_ui.rs:908`](../../ui/dr-ui/src/masks_ui.rs#L908), [`ui/dr-ui/ui/app.slint:1012`](../../ui/dr-ui/ui/app.slint#L1012), [`ui/dr-ui/ui/app.slint:2216`](../../ui/dr-ui/ui/app.slint#L2216), [`ui/dr-ui/ui/masks.slint:1126`](../../ui/dr-ui/ui/masks.slint#L1126), [`ui/dr-ui/ui/masks.slint:453`](../../ui/dr-ui/ui/masks.slint#L453), [`ui/dr-ui/ui/masks.slint:774`](../../ui/dr-ui/ui/masks.slint#L774), [`ui/dr-ui/ui/masks.slint:848`](../../ui/dr-ui/ui/masks.slint#L848), [`ui/dr-ui/ui/masks.slint:864`](../../ui/dr-ui/ui/masks.slint#L864) |
+| FR-DEV-19b | [`ui/dr-ui/src/develop/mask_ops.rs:606`](../../ui/dr-ui/src/develop/mask_ops.rs#L606), [`ui/dr-ui/src/develop/masks.rs:592`](../../ui/dr-ui/src/develop/masks.rs#L592), [`ui/dr-ui/src/develop/session.rs:197`](../../ui/dr-ui/src/develop/session.rs#L197), [`ui/dr-ui/src/develop/session.rs:204`](../../ui/dr-ui/src/develop/session.rs#L204), [`ui/dr-ui/src/labels.rs:67`](../../ui/dr-ui/src/labels.rs#L67), [`ui/dr-ui/src/masks_ui.rs:1188`](../../ui/dr-ui/src/masks_ui.rs#L1188), [`ui/dr-ui/src/masks_ui.rs:1407`](../../ui/dr-ui/src/masks_ui.rs#L1407), [`ui/dr-ui/src/masks_ui.rs:1435`](../../ui/dr-ui/src/masks_ui.rs#L1435), [`ui/dr-ui/src/masks_ui.rs:1778`](../../ui/dr-ui/src/masks_ui.rs#L1778), [`ui/dr-ui/src/masks_ui.rs:908`](../../ui/dr-ui/src/masks_ui.rs#L908), [`ui/dr-ui/ui/app.slint:1952`](../../ui/dr-ui/ui/app.slint#L1952), [`ui/dr-ui/ui/app.slint:755`](../../ui/dr-ui/ui/app.slint#L755), [`ui/dr-ui/ui/masks.slint:1126`](../../ui/dr-ui/ui/masks.slint#L1126), [`ui/dr-ui/ui/masks.slint:453`](../../ui/dr-ui/ui/masks.slint#L453), [`ui/dr-ui/ui/masks.slint:774`](../../ui/dr-ui/ui/masks.slint#L774), [`ui/dr-ui/ui/masks.slint:848`](../../ui/dr-ui/ui/masks.slint#L848), [`ui/dr-ui/ui/masks.slint:864`](../../ui/dr-ui/ui/masks.slint#L864) |
| FR-DEV-19c | [`core/dr-gpu/src/mask.rs:715`](../../core/dr-gpu/src/mask.rs#L715), [`core/dr-gpu/tests/local_adjustments.rs:830`](../../core/dr-gpu/tests/local_adjustments.rs#L830), [`core/dr-gpu/tests/local_adjustments.rs:887`](../../core/dr-gpu/tests/local_adjustments.rs#L887), [`core/dr-gpu/tests/local_adjustments.rs:922`](../../core/dr-gpu/tests/local_adjustments.rs#L922), [`core/dr-gpu/tests/local_adjustments.rs:967`](../../core/dr-gpu/tests/local_adjustments.rs#L967), [`core/dr-pipeline/src/graph.rs:893`](../../core/dr-pipeline/src/graph.rs#L893), [`core/dr-pipeline/src/mask.rs:1796`](../../core/dr-pipeline/src/mask.rs#L1796), [`core/dr-pipeline/src/mask.rs:1822`](../../core/dr-pipeline/src/mask.rs#L1822), [`core/dr-pipeline/src/mask.rs:1837`](../../core/dr-pipeline/src/mask.rs#L1837), [`core/dr-pipeline/src/mask.rs:1957`](../../core/dr-pipeline/src/mask.rs#L1957), [`core/dr-pipeline/src/mask.rs:2005`](../../core/dr-pipeline/src/mask.rs#L2005), [`core/dr-pipeline/src/mask.rs:2149`](../../core/dr-pipeline/src/mask.rs#L2149), [`core/dr-pipeline/src/mask.rs:2386`](../../core/dr-pipeline/src/mask.rs#L2386), [`core/dr-pipeline/src/operation.rs:1748`](../../core/dr-pipeline/src/operation.rs#L1748), [`core/dr-pipeline/src/operation.rs:588`](../../core/dr-pipeline/src/operation.rs#L588), [`core/dr-pipeline/src/operation.rs:863`](../../core/dr-pipeline/src/operation.rs#L863), [`ui/dr-ui/src/develop/mask_ops.rs:1199`](../../ui/dr-ui/src/develop/mask_ops.rs#L1199), [`ui/dr-ui/src/develop/mask_ops.rs:1235`](../../ui/dr-ui/src/develop/mask_ops.rs#L1235), [`ui/dr-ui/src/develop/mask_ops.rs:318`](../../ui/dr-ui/src/develop/mask_ops.rs#L318), [`ui/dr-ui/src/develop/mask_ops.rs:58`](../../ui/dr-ui/src/develop/mask_ops.rs#L58), [`ui/dr-ui/src/develop/masks.rs:12`](../../ui/dr-ui/src/develop/masks.rs#L12), [`ui/dr-ui/src/develop/masks.rs:176`](../../ui/dr-ui/src/develop/masks.rs#L176), [`ui/dr-ui/src/develop/masks.rs:21`](../../ui/dr-ui/src/develop/masks.rs#L21), [`ui/dr-ui/src/develop/masks.rs:43`](../../ui/dr-ui/src/develop/masks.rs#L43), [`ui/dr-ui/src/develop/render.rs:178`](../../ui/dr-ui/src/develop/render.rs#L178), [`ui/dr-ui/src/develop/session.rs:223`](../../ui/dr-ui/src/develop/session.rs#L223), [`ui/dr-ui/src/develop/session.rs:232`](../../ui/dr-ui/src/develop/session.rs#L232), [`ui/dr-ui/src/masks_ui.rs:1024`](../../ui/dr-ui/src/masks_ui.rs#L1024), [`ui/dr-ui/src/masks_ui.rs:1407`](../../ui/dr-ui/src/masks_ui.rs#L1407), [`ui/dr-ui/src/masks_ui.rs:152`](../../ui/dr-ui/src/masks_ui.rs#L152), [`ui/dr-ui/src/masks_ui.rs:1778`](../../ui/dr-ui/src/masks_ui.rs#L1778), [`ui/dr-ui/src/masks_ui.rs:291`](../../ui/dr-ui/src/masks_ui.rs#L291), [`ui/dr-ui/src/masks_ui.rs:317`](../../ui/dr-ui/src/masks_ui.rs#L317), [`ui/dr-ui/src/masks_ui.rs:677`](../../ui/dr-ui/src/masks_ui.rs#L677), [`ui/dr-ui/src/masks_ui.rs:996`](../../ui/dr-ui/src/masks_ui.rs#L996), [`ui/dr-ui/ui/icons.slint:339`](../../ui/dr-ui/ui/icons.slint#L339), [`ui/dr-ui/ui/masks.slint:1091`](../../ui/dr-ui/ui/masks.slint#L1091), [`ui/dr-ui/ui/masks.slint:183`](../../ui/dr-ui/ui/masks.slint#L183), [`ui/dr-ui/ui/masks.slint:292`](../../ui/dr-ui/ui/masks.slint#L292), [`ui/dr-ui/ui/masks.slint:517`](../../ui/dr-ui/ui/masks.slint#L517), [`ui/dr-ui/ui/masks.slint:70`](../../ui/dr-ui/ui/masks.slint#L70), [`ui/dr-ui/ui/masks.slint:782`](../../ui/dr-ui/ui/masks.slint#L782), [`ui/dr-ui/ui/masks.slint:850`](../../ui/dr-ui/ui/masks.slint#L850), [`ui/dr-ui/ui/masks.slint:938`](../../ui/dr-ui/ui/masks.slint#L938) |
| 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:2443`](../../core/dr-gpu/src/adjust.rs#L2443), [`core/dr-gpu/src/adjust.rs:679`](../../core/dr-gpu/src/adjust.rs#L679), [`core/dr-gpu/src/adjust.rs:798`](../../core/dr-gpu/src/adjust.rs#L798), [`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:1348`](../../core/dr-pipeline/src/graph.rs#L1348), [`core/dr-pipeline/src/graph.rs:1379`](../../core/dr-pipeline/src/graph.rs#L1379), [`core/dr-pipeline/src/graph.rs:1402`](../../core/dr-pipeline/src/graph.rs#L1402), [`core/dr-pipeline/src/graph.rs:1440`](../../core/dr-pipeline/src/graph.rs#L1440), [`core/dr-pipeline/src/graph.rs:1471`](../../core/dr-pipeline/src/graph.rs#L1471), [`core/dr-pipeline/src/graph.rs:225`](../../core/dr-pipeline/src/graph.rs#L225), [`core/dr-pipeline/src/graph.rs:306`](../../core/dr-pipeline/src/graph.rs#L306), [`core/dr-pipeline/src/graph.rs:344`](../../core/dr-pipeline/src/graph.rs#L344), [`core/dr-pipeline/src/graph.rs:350`](../../core/dr-pipeline/src/graph.rs#L350), [`core/dr-pipeline/src/graph.rs:860`](../../core/dr-pipeline/src/graph.rs#L860), [`core/dr-pipeline/src/graph.rs:952`](../../core/dr-pipeline/src/graph.rs#L952), [`core/dr-pipeline/src/lens.rs:93`](../../core/dr-pipeline/src/lens.rs#L93), [`core/dr-pipeline/src/mask.rs:205`](../../core/dr-pipeline/src/mask.rs#L205), [`core/dr-pipeline/src/mask.rs:558`](../../core/dr-pipeline/src/mask.rs#L558), [`core/dr-pipeline/src/neutral.rs:1`](../../core/dr-pipeline/src/neutral.rs#L1), [`core/dr-pipeline/src/neutral.rs:306`](../../core/dr-pipeline/src/neutral.rs#L306), [`core/dr-pipeline/src/neutral.rs:322`](../../core/dr-pipeline/src/neutral.rs#L322), [`core/dr-pipeline/src/neutral.rs:338`](../../core/dr-pipeline/src/neutral.rs#L338), [`core/dr-pipeline/src/neutral.rs:360`](../../core/dr-pipeline/src/neutral.rs#L360), [`core/dr-pipeline/src/neutral.rs:81`](../../core/dr-pipeline/src/neutral.rs#L81), [`core/dr-pipeline/src/operation.rs:330`](../../core/dr-pipeline/src/operation.rs#L330), [`core/dr-pipeline/src/operation.rs:565`](../../core/dr-pipeline/src/operation.rs#L565), [`core/dr-pipeline/src/operation.rs:637`](../../core/dr-pipeline/src/operation.rs#L637), [`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/preset.rs:751`](../../core/dr-pipeline/src/preset.rs#L751), [`core/dr-pipeline/src/sidecar.rs:1400`](../../core/dr-pipeline/src/sidecar.rs#L1400), [`core/dr-pipeline/src/sidecar.rs:192`](../../core/dr-pipeline/src/sidecar.rs#L192), [`core/dr-pipeline/src/sidecar.rs:2232`](../../core/dr-pipeline/src/sidecar.rs#L2232), [`core/dr-pipeline/src/sidecar.rs:2312`](../../core/dr-pipeline/src/sidecar.rs#L2312), [`core/dr-pipeline/tests/tone_curve.rs:1`](../../core/dr-pipeline/tests/tone_curve.rs#L1), [`core/dr-segment/src/refine.rs:937`](../../core/dr-segment/src/refine.rs#L937), [`ui/dr-ui/src/develop/curves.rs:163`](../../ui/dr-ui/src/develop/curves.rs#L163), [`ui/dr-ui/src/develop/framing.rs:10`](../../ui/dr-ui/src/develop/framing.rs#L10), [`ui/dr-ui/src/develop/framing.rs:182`](../../ui/dr-ui/src/develop/framing.rs#L182), [`ui/dr-ui/src/develop/framing.rs:212`](../../ui/dr-ui/src/develop/framing.rs#L212), [`ui/dr-ui/src/develop/framing.rs:278`](../../ui/dr-ui/src/develop/framing.rs#L278), [`ui/dr-ui/src/develop/framing.rs:292`](../../ui/dr-ui/src/develop/framing.rs#L292), [`ui/dr-ui/src/develop/framing.rs:494`](../../ui/dr-ui/src/develop/framing.rs#L494), [`ui/dr-ui/src/develop/framing.rs:71`](../../ui/dr-ui/src/develop/framing.rs#L71), [`ui/dr-ui/src/develop/mask_ops.rs:1076`](../../ui/dr-ui/src/develop/mask_ops.rs#L1076), [`ui/dr-ui/src/develop/mask_ops.rs:1340`](../../ui/dr-ui/src/develop/mask_ops.rs#L1340), [`ui/dr-ui/src/develop/mask_ops.rs:178`](../../ui/dr-ui/src/develop/mask_ops.rs#L178), [`ui/dr-ui/src/develop/mask_ops.rs:969`](../../ui/dr-ui/src/develop/mask_ops.rs#L969), [`ui/dr-ui/src/develop/masks.rs:262`](../../ui/dr-ui/src/develop/masks.rs#L262), [`ui/dr-ui/src/develop/masks.rs:360`](../../ui/dr-ui/src/develop/masks.rs#L360), [`ui/dr-ui/src/develop/masks.rs:740`](../../ui/dr-ui/src/develop/masks.rs#L740), [`ui/dr-ui/src/develop/masks.rs:770`](../../ui/dr-ui/src/develop/masks.rs#L770), [`ui/dr-ui/src/develop/render.rs:1039`](../../ui/dr-ui/src/develop/render.rs#L1039), [`ui/dr-ui/src/develop/rows.rs:106`](../../ui/dr-ui/src/develop/rows.rs#L106), [`ui/dr-ui/src/develop/rows.rs:195`](../../ui/dr-ui/src/develop/rows.rs#L195), [`ui/dr-ui/src/develop/rows.rs:231`](../../ui/dr-ui/src/develop/rows.rs#L231), [`ui/dr-ui/src/develop/rows.rs:679`](../../ui/dr-ui/src/develop/rows.rs#L679), [`ui/dr-ui/src/develop/segmentation.rs:139`](../../ui/dr-ui/src/develop/segmentation.rs#L139), [`ui/dr-ui/src/develop/segmentation.rs:302`](../../ui/dr-ui/src/develop/segmentation.rs#L302), [`ui/dr-ui/src/develop/segmentation.rs:339`](../../ui/dr-ui/src/develop/segmentation.rs#L339), [`ui/dr-ui/src/develop/segmentation.rs:572`](../../ui/dr-ui/src/develop/segmentation.rs#L572), [`ui/dr-ui/src/develop/segmentation.rs:590`](../../ui/dr-ui/src/develop/segmentation.rs#L590), [`ui/dr-ui/src/develop/segmentation.rs:604`](../../ui/dr-ui/src/develop/segmentation.rs#L604), [`ui/dr-ui/src/develop/segmentation.rs:626`](../../ui/dr-ui/src/develop/segmentation.rs#L626), [`ui/dr-ui/src/develop/segmentation.rs:77`](../../ui/dr-ui/src/develop/segmentation.rs#L77), [`ui/dr-ui/src/develop/segmentation.rs:806`](../../ui/dr-ui/src/develop/segmentation.rs#L806), [`ui/dr-ui/src/develop/session.rs:158`](../../ui/dr-ui/src/develop/session.rs#L158), [`ui/dr-ui/src/develop/session.rs:251`](../../ui/dr-ui/src/develop/session.rs#L251), [`ui/dr-ui/src/develop/session.rs:280`](../../ui/dr-ui/src/develop/session.rs#L280), [`ui/dr-ui/src/develop/session.rs:429`](../../ui/dr-ui/src/develop/session.rs#L429), [`ui/dr-ui/src/develop/session.rs:489`](../../ui/dr-ui/src/develop/session.rs#L489), [`ui/dr-ui/src/develop/session.rs:561`](../../ui/dr-ui/src/develop/session.rs#L561), [`ui/dr-ui/src/develop/session.rs:711`](../../ui/dr-ui/src/develop/session.rs#L711), [`ui/dr-ui/src/develop/white_balance.rs:11`](../../ui/dr-ui/src/develop/white_balance.rs#L11), [`ui/dr-ui/src/develop/white_balance.rs:162`](../../ui/dr-ui/src/develop/white_balance.rs#L162), [`ui/dr-ui/src/develop/white_balance.rs:193`](../../ui/dr-ui/src/develop/white_balance.rs#L193), [`ui/dr-ui/src/develop/white_balance.rs:276`](../../ui/dr-ui/src/develop/white_balance.rs#L276), [`ui/dr-ui/src/develop/white_balance.rs:338`](../../ui/dr-ui/src/develop/white_balance.rs#L338), [`ui/dr-ui/src/develop_ui.rs:1040`](../../ui/dr-ui/src/develop_ui.rs#L1040), [`ui/dr-ui/src/develop_ui.rs:1094`](../../ui/dr-ui/src/develop_ui.rs#L1094), [`ui/dr-ui/src/develop_ui.rs:117`](../../ui/dr-ui/src/develop_ui.rs#L117), [`ui/dr-ui/src/develop_ui.rs:406`](../../ui/dr-ui/src/develop_ui.rs#L406), [`ui/dr-ui/src/develop_ui.rs:626`](../../ui/dr-ui/src/develop_ui.rs#L626), [`ui/dr-ui/src/develop_ui.rs:964`](../../ui/dr-ui/src/develop_ui.rs#L964), [`ui/dr-ui/src/labels.rs:35`](../../ui/dr-ui/src/labels.rs#L35), [`ui/dr-ui/src/lib.rs:2192`](../../ui/dr-ui/src/lib.rs#L2192), [`ui/dr-ui/src/lib.rs:420`](../../ui/dr-ui/src/lib.rs#L420), [`ui/dr-ui/src/lib.rs:449`](../../ui/dr-ui/src/lib.rs#L449), [`ui/dr-ui/src/lib.rs:555`](../../ui/dr-ui/src/lib.rs#L555), [`ui/dr-ui/src/lib.rs:579`](../../ui/dr-ui/src/lib.rs#L579), [`ui/dr-ui/src/library/sidecar.rs:63`](../../ui/dr-ui/src/library/sidecar.rs#L63), [`ui/dr-ui/src/masks_ui.rs:1537`](../../ui/dr-ui/src/masks_ui.rs#L1537), [`ui/dr-ui/src/masks_ui.rs:1651`](../../ui/dr-ui/src/masks_ui.rs#L1651), [`ui/dr-ui/src/masks_ui.rs:339`](../../ui/dr-ui/src/masks_ui.rs#L339), [`ui/dr-ui/src/masks_ui.rs:44`](../../ui/dr-ui/src/masks_ui.rs#L44), [`ui/dr-ui/src/presets.rs:414`](../../ui/dr-ui/src/presets.rs#L414), [`ui/dr-ui/src/segmentation.rs:117`](../../ui/dr-ui/src/segmentation.rs#L117), [`ui/dr-ui/src/segmentation.rs:353`](../../ui/dr-ui/src/segmentation.rs#L353), [`ui/dr-ui/src/segmentation.rs:369`](../../ui/dr-ui/src/segmentation.rs#L369), [`ui/dr-ui/src/segmentation.rs:499`](../../ui/dr-ui/src/segmentation.rs#L499), [`ui/dr-ui/src/segmentation.rs:527`](../../ui/dr-ui/src/segmentation.rs#L527), [`ui/dr-ui/ui/adjust.slint:1019`](../../ui/dr-ui/ui/adjust.slint#L1019), [`ui/dr-ui/ui/adjust.slint:126`](../../ui/dr-ui/ui/adjust.slint#L126), [`ui/dr-ui/ui/adjust.slint:1496`](../../ui/dr-ui/ui/adjust.slint#L1496), [`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:624`](../../ui/dr-ui/ui/adjust.slint#L624), [`ui/dr-ui/ui/adjust.slint:650`](../../ui/dr-ui/ui/adjust.slint#L650), [`ui/dr-ui/ui/adjust.slint:669`](../../ui/dr-ui/ui/adjust.slint#L669), [`ui/dr-ui/ui/adjust.slint:790`](../../ui/dr-ui/ui/adjust.slint#L790), [`ui/dr-ui/ui/adjust.slint:947`](../../ui/dr-ui/ui/adjust.slint#L947), [`ui/dr-ui/ui/app.slint:189`](../../ui/dr-ui/ui/app.slint#L189), [`ui/dr-ui/ui/app.slint:2281`](../../ui/dr-ui/ui/app.slint#L2281), [`ui/dr-ui/ui/app.slint:2341`](../../ui/dr-ui/ui/app.slint#L2341), [`ui/dr-ui/ui/develop.slint:223`](../../ui/dr-ui/ui/develop.slint#L223), [`ui/dr-ui/ui/masks.slint:1216`](../../ui/dr-ui/ui/masks.slint#L1216), [`ui/dr-ui/ui/masks.slint:753`](../../ui/dr-ui/ui/masks.slint#L753), [`ui/dr-ui/ui/masks.slint:812`](../../ui/dr-ui/ui/masks.slint#L812) |
-| 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:393`](../../core/dr-pipeline/src/graph.rs#L393), [`core/dr-pipeline/src/graph.rs:47`](../../core/dr-pipeline/src/graph.rs#L47), [`core/dr-pipeline/src/graph.rs:534`](../../core/dr-pipeline/src/graph.rs#L534), [`core/dr-pipeline/src/graph.rs:60`](../../core/dr-pipeline/src/graph.rs#L60), [`core/dr-pipeline/src/mask.rs:1699`](../../core/dr-pipeline/src/mask.rs#L1699), [`core/dr-pipeline/src/neutral.rs:1`](../../core/dr-pipeline/src/neutral.rs#L1), [`core/dr-pipeline/src/neutral.rs:378`](../../core/dr-pipeline/src/neutral.rs#L378), [`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/curves.rs:36`](../../ui/dr-ui/src/develop/curves.rs#L36), [`ui/dr-ui/src/develop/rows.rs:118`](../../ui/dr-ui/src/develop/rows.rs#L118), [`ui/dr-ui/src/develop/rows.rs:679`](../../ui/dr-ui/src/develop/rows.rs#L679), [`ui/dr-ui/src/develop/rows.rs:877`](../../ui/dr-ui/src/develop/rows.rs#L877), [`ui/dr-ui/src/lib.rs:880`](../../ui/dr-ui/src/lib.rs#L880), [`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:2525`](../../ui/dr-ui/ui/app.slint#L2525) |
-| 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:2736`](../../ui/dr-ui/ui/app.slint#L2736) |
+| FR-DEV-3 | [`core/dr-gpu/src/adjust.rs:2443`](../../core/dr-gpu/src/adjust.rs#L2443), [`core/dr-gpu/src/adjust.rs:679`](../../core/dr-gpu/src/adjust.rs#L679), [`core/dr-gpu/src/adjust.rs:798`](../../core/dr-gpu/src/adjust.rs#L798), [`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:1348`](../../core/dr-pipeline/src/graph.rs#L1348), [`core/dr-pipeline/src/graph.rs:1379`](../../core/dr-pipeline/src/graph.rs#L1379), [`core/dr-pipeline/src/graph.rs:1402`](../../core/dr-pipeline/src/graph.rs#L1402), [`core/dr-pipeline/src/graph.rs:1440`](../../core/dr-pipeline/src/graph.rs#L1440), [`core/dr-pipeline/src/graph.rs:1471`](../../core/dr-pipeline/src/graph.rs#L1471), [`core/dr-pipeline/src/graph.rs:225`](../../core/dr-pipeline/src/graph.rs#L225), [`core/dr-pipeline/src/graph.rs:306`](../../core/dr-pipeline/src/graph.rs#L306), [`core/dr-pipeline/src/graph.rs:344`](../../core/dr-pipeline/src/graph.rs#L344), [`core/dr-pipeline/src/graph.rs:350`](../../core/dr-pipeline/src/graph.rs#L350), [`core/dr-pipeline/src/graph.rs:860`](../../core/dr-pipeline/src/graph.rs#L860), [`core/dr-pipeline/src/graph.rs:952`](../../core/dr-pipeline/src/graph.rs#L952), [`core/dr-pipeline/src/lens.rs:93`](../../core/dr-pipeline/src/lens.rs#L93), [`core/dr-pipeline/src/mask.rs:205`](../../core/dr-pipeline/src/mask.rs#L205), [`core/dr-pipeline/src/mask.rs:558`](../../core/dr-pipeline/src/mask.rs#L558), [`core/dr-pipeline/src/neutral.rs:1`](../../core/dr-pipeline/src/neutral.rs#L1), [`core/dr-pipeline/src/neutral.rs:306`](../../core/dr-pipeline/src/neutral.rs#L306), [`core/dr-pipeline/src/neutral.rs:322`](../../core/dr-pipeline/src/neutral.rs#L322), [`core/dr-pipeline/src/neutral.rs:338`](../../core/dr-pipeline/src/neutral.rs#L338), [`core/dr-pipeline/src/neutral.rs:360`](../../core/dr-pipeline/src/neutral.rs#L360), [`core/dr-pipeline/src/neutral.rs:81`](../../core/dr-pipeline/src/neutral.rs#L81), [`core/dr-pipeline/src/operation.rs:330`](../../core/dr-pipeline/src/operation.rs#L330), [`core/dr-pipeline/src/operation.rs:565`](../../core/dr-pipeline/src/operation.rs#L565), [`core/dr-pipeline/src/operation.rs:637`](../../core/dr-pipeline/src/operation.rs#L637), [`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/preset.rs:751`](../../core/dr-pipeline/src/preset.rs#L751), [`core/dr-pipeline/src/sidecar.rs:1400`](../../core/dr-pipeline/src/sidecar.rs#L1400), [`core/dr-pipeline/src/sidecar.rs:192`](../../core/dr-pipeline/src/sidecar.rs#L192), [`core/dr-pipeline/src/sidecar.rs:2232`](../../core/dr-pipeline/src/sidecar.rs#L2232), [`core/dr-pipeline/src/sidecar.rs:2312`](../../core/dr-pipeline/src/sidecar.rs#L2312), [`core/dr-pipeline/tests/tone_curve.rs:1`](../../core/dr-pipeline/tests/tone_curve.rs#L1), [`core/dr-segment/src/refine.rs:937`](../../core/dr-segment/src/refine.rs#L937), [`ui/dr-ui/src/develop/curves.rs:163`](../../ui/dr-ui/src/develop/curves.rs#L163), [`ui/dr-ui/src/develop/framing.rs:10`](../../ui/dr-ui/src/develop/framing.rs#L10), [`ui/dr-ui/src/develop/framing.rs:182`](../../ui/dr-ui/src/develop/framing.rs#L182), [`ui/dr-ui/src/develop/framing.rs:212`](../../ui/dr-ui/src/develop/framing.rs#L212), [`ui/dr-ui/src/develop/framing.rs:278`](../../ui/dr-ui/src/develop/framing.rs#L278), [`ui/dr-ui/src/develop/framing.rs:292`](../../ui/dr-ui/src/develop/framing.rs#L292), [`ui/dr-ui/src/develop/framing.rs:494`](../../ui/dr-ui/src/develop/framing.rs#L494), [`ui/dr-ui/src/develop/framing.rs:71`](../../ui/dr-ui/src/develop/framing.rs#L71), [`ui/dr-ui/src/develop/mask_ops.rs:1076`](../../ui/dr-ui/src/develop/mask_ops.rs#L1076), [`ui/dr-ui/src/develop/mask_ops.rs:1340`](../../ui/dr-ui/src/develop/mask_ops.rs#L1340), [`ui/dr-ui/src/develop/mask_ops.rs:178`](../../ui/dr-ui/src/develop/mask_ops.rs#L178), [`ui/dr-ui/src/develop/mask_ops.rs:969`](../../ui/dr-ui/src/develop/mask_ops.rs#L969), [`ui/dr-ui/src/develop/masks.rs:262`](../../ui/dr-ui/src/develop/masks.rs#L262), [`ui/dr-ui/src/develop/masks.rs:360`](../../ui/dr-ui/src/develop/masks.rs#L360), [`ui/dr-ui/src/develop/masks.rs:740`](../../ui/dr-ui/src/develop/masks.rs#L740), [`ui/dr-ui/src/develop/masks.rs:770`](../../ui/dr-ui/src/develop/masks.rs#L770), [`ui/dr-ui/src/develop/render.rs:1039`](../../ui/dr-ui/src/develop/render.rs#L1039), [`ui/dr-ui/src/develop/rows.rs:106`](../../ui/dr-ui/src/develop/rows.rs#L106), [`ui/dr-ui/src/develop/rows.rs:195`](../../ui/dr-ui/src/develop/rows.rs#L195), [`ui/dr-ui/src/develop/rows.rs:231`](../../ui/dr-ui/src/develop/rows.rs#L231), [`ui/dr-ui/src/develop/rows.rs:679`](../../ui/dr-ui/src/develop/rows.rs#L679), [`ui/dr-ui/src/develop/segmentation.rs:139`](../../ui/dr-ui/src/develop/segmentation.rs#L139), [`ui/dr-ui/src/develop/segmentation.rs:302`](../../ui/dr-ui/src/develop/segmentation.rs#L302), [`ui/dr-ui/src/develop/segmentation.rs:339`](../../ui/dr-ui/src/develop/segmentation.rs#L339), [`ui/dr-ui/src/develop/segmentation.rs:572`](../../ui/dr-ui/src/develop/segmentation.rs#L572), [`ui/dr-ui/src/develop/segmentation.rs:590`](../../ui/dr-ui/src/develop/segmentation.rs#L590), [`ui/dr-ui/src/develop/segmentation.rs:604`](../../ui/dr-ui/src/develop/segmentation.rs#L604), [`ui/dr-ui/src/develop/segmentation.rs:626`](../../ui/dr-ui/src/develop/segmentation.rs#L626), [`ui/dr-ui/src/develop/segmentation.rs:77`](../../ui/dr-ui/src/develop/segmentation.rs#L77), [`ui/dr-ui/src/develop/segmentation.rs:806`](../../ui/dr-ui/src/develop/segmentation.rs#L806), [`ui/dr-ui/src/develop/session.rs:158`](../../ui/dr-ui/src/develop/session.rs#L158), [`ui/dr-ui/src/develop/session.rs:251`](../../ui/dr-ui/src/develop/session.rs#L251), [`ui/dr-ui/src/develop/session.rs:280`](../../ui/dr-ui/src/develop/session.rs#L280), [`ui/dr-ui/src/develop/session.rs:429`](../../ui/dr-ui/src/develop/session.rs#L429), [`ui/dr-ui/src/develop/session.rs:489`](../../ui/dr-ui/src/develop/session.rs#L489), [`ui/dr-ui/src/develop/session.rs:561`](../../ui/dr-ui/src/develop/session.rs#L561), [`ui/dr-ui/src/develop/session.rs:711`](../../ui/dr-ui/src/develop/session.rs#L711), [`ui/dr-ui/src/develop/white_balance.rs:11`](../../ui/dr-ui/src/develop/white_balance.rs#L11), [`ui/dr-ui/src/develop/white_balance.rs:162`](../../ui/dr-ui/src/develop/white_balance.rs#L162), [`ui/dr-ui/src/develop/white_balance.rs:193`](../../ui/dr-ui/src/develop/white_balance.rs#L193), [`ui/dr-ui/src/develop/white_balance.rs:276`](../../ui/dr-ui/src/develop/white_balance.rs#L276), [`ui/dr-ui/src/develop/white_balance.rs:338`](../../ui/dr-ui/src/develop/white_balance.rs#L338), [`ui/dr-ui/src/develop_ui.rs:1048`](../../ui/dr-ui/src/develop_ui.rs#L1048), [`ui/dr-ui/src/develop_ui.rs:1102`](../../ui/dr-ui/src/develop_ui.rs#L1102), [`ui/dr-ui/src/develop_ui.rs:117`](../../ui/dr-ui/src/develop_ui.rs#L117), [`ui/dr-ui/src/develop_ui.rs:414`](../../ui/dr-ui/src/develop_ui.rs#L414), [`ui/dr-ui/src/develop_ui.rs:634`](../../ui/dr-ui/src/develop_ui.rs#L634), [`ui/dr-ui/src/develop_ui.rs:972`](../../ui/dr-ui/src/develop_ui.rs#L972), [`ui/dr-ui/src/labels.rs:35`](../../ui/dr-ui/src/labels.rs#L35), [`ui/dr-ui/src/lib.rs:2193`](../../ui/dr-ui/src/lib.rs#L2193), [`ui/dr-ui/src/lib.rs:421`](../../ui/dr-ui/src/lib.rs#L421), [`ui/dr-ui/src/lib.rs:450`](../../ui/dr-ui/src/lib.rs#L450), [`ui/dr-ui/src/lib.rs:556`](../../ui/dr-ui/src/lib.rs#L556), [`ui/dr-ui/src/lib.rs:580`](../../ui/dr-ui/src/lib.rs#L580), [`ui/dr-ui/src/library/sidecar.rs:63`](../../ui/dr-ui/src/library/sidecar.rs#L63), [`ui/dr-ui/src/masks_ui.rs:1537`](../../ui/dr-ui/src/masks_ui.rs#L1537), [`ui/dr-ui/src/masks_ui.rs:1651`](../../ui/dr-ui/src/masks_ui.rs#L1651), [`ui/dr-ui/src/masks_ui.rs:339`](../../ui/dr-ui/src/masks_ui.rs#L339), [`ui/dr-ui/src/masks_ui.rs:44`](../../ui/dr-ui/src/masks_ui.rs#L44), [`ui/dr-ui/src/presets.rs:414`](../../ui/dr-ui/src/presets.rs#L414), [`ui/dr-ui/src/segmentation.rs:117`](../../ui/dr-ui/src/segmentation.rs#L117), [`ui/dr-ui/src/segmentation.rs:353`](../../ui/dr-ui/src/segmentation.rs#L353), [`ui/dr-ui/src/segmentation.rs:369`](../../ui/dr-ui/src/segmentation.rs#L369), [`ui/dr-ui/src/segmentation.rs:499`](../../ui/dr-ui/src/segmentation.rs#L499), [`ui/dr-ui/src/segmentation.rs:527`](../../ui/dr-ui/src/segmentation.rs#L527), [`ui/dr-ui/ui/adjust.slint:1019`](../../ui/dr-ui/ui/adjust.slint#L1019), [`ui/dr-ui/ui/adjust.slint:126`](../../ui/dr-ui/ui/adjust.slint#L126), [`ui/dr-ui/ui/adjust.slint:1496`](../../ui/dr-ui/ui/adjust.slint#L1496), [`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:624`](../../ui/dr-ui/ui/adjust.slint#L624), [`ui/dr-ui/ui/adjust.slint:650`](../../ui/dr-ui/ui/adjust.slint#L650), [`ui/dr-ui/ui/adjust.slint:669`](../../ui/dr-ui/ui/adjust.slint#L669), [`ui/dr-ui/ui/adjust.slint:790`](../../ui/dr-ui/ui/adjust.slint#L790), [`ui/dr-ui/ui/adjust.slint:947`](../../ui/dr-ui/ui/adjust.slint#L947), [`ui/dr-ui/ui/app.slint:190`](../../ui/dr-ui/ui/app.slint#L190), [`ui/dr-ui/ui/app.slint:2017`](../../ui/dr-ui/ui/app.slint#L2017), [`ui/dr-ui/ui/app.slint:2076`](../../ui/dr-ui/ui/app.slint#L2076), [`ui/dr-ui/ui/develop.slint:223`](../../ui/dr-ui/ui/develop.slint#L223), [`ui/dr-ui/ui/masks.slint:1216`](../../ui/dr-ui/ui/masks.slint#L1216), [`ui/dr-ui/ui/masks.slint:753`](../../ui/dr-ui/ui/masks.slint#L753), [`ui/dr-ui/ui/masks.slint:812`](../../ui/dr-ui/ui/masks.slint#L812) |
+| 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:393`](../../core/dr-pipeline/src/graph.rs#L393), [`core/dr-pipeline/src/graph.rs:47`](../../core/dr-pipeline/src/graph.rs#L47), [`core/dr-pipeline/src/graph.rs:534`](../../core/dr-pipeline/src/graph.rs#L534), [`core/dr-pipeline/src/graph.rs:60`](../../core/dr-pipeline/src/graph.rs#L60), [`core/dr-pipeline/src/mask.rs:1699`](../../core/dr-pipeline/src/mask.rs#L1699), [`core/dr-pipeline/src/neutral.rs:1`](../../core/dr-pipeline/src/neutral.rs#L1), [`core/dr-pipeline/src/neutral.rs:378`](../../core/dr-pipeline/src/neutral.rs#L378), [`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/curves.rs:36`](../../ui/dr-ui/src/develop/curves.rs#L36), [`ui/dr-ui/src/develop/rows.rs:118`](../../ui/dr-ui/src/develop/rows.rs#L118), [`ui/dr-ui/src/develop/rows.rs:679`](../../ui/dr-ui/src/develop/rows.rs#L679), [`ui/dr-ui/src/develop/rows.rs:877`](../../ui/dr-ui/src/develop/rows.rs#L877), [`ui/dr-ui/src/lib.rs:881`](../../ui/dr-ui/src/lib.rs#L881), [`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:2260`](../../ui/dr-ui/ui/app.slint#L2260) |
+| 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:2471`](../../ui/dr-ui/ui/app.slint#L2471) |
| FR-DEV-3c | [`core/dr-pipeline/ops/exposure.yaml:1`](../../core/dr-pipeline/ops/exposure.yaml#L1), [`core/dr-pipeline/src/graph.rs:393`](../../core/dr-pipeline/src/graph.rs#L393), [`core/dr-pipeline/src/graph.rs:47`](../../core/dr-pipeline/src/graph.rs#L47), [`core/dr-pipeline/src/mask.rs:1699`](../../core/dr-pipeline/src/mask.rs#L1699), [`core/dr-pipeline/src/preset.rs:751`](../../core/dr-pipeline/src/preset.rs#L751), [`ui/dr-ui/src/develop/rows.rs:928`](../../ui/dr-ui/src/develop/rows.rs#L928) |
| FR-DEV-3d | [`core/dr-gpu/src/adjust.rs:1014`](../../core/dr-gpu/src/adjust.rs#L1014), [`core/dr-gpu/src/adjust.rs:1107`](../../core/dr-gpu/src/adjust.rs#L1107), [`core/dr-gpu/src/adjust.rs:114`](../../core/dr-gpu/src/adjust.rs#L114), [`core/dr-gpu/src/adjust.rs:798`](../../core/dr-gpu/src/adjust.rs#L798), [`core/dr-gpu/src/adjust.rs:84`](../../core/dr-gpu/src/adjust.rs#L84), [`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:991`](../../core/dr-pipeline/src/graph.rs#L991), [`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:771`](../../core/dr-decode/src/lib.rs#L771), [`core/dr-decode/src/lib.rs:811`](../../core/dr-decode/src/lib.rs#L811), [`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:473`](../../core/dr-decode/src/profile.rs#L473), [`core/dr-decode/src/profile.rs:507`](../../core/dr-decode/src/profile.rs#L507), [`core/dr-decode/src/profile.rs:678`](../../core/dr-decode/src/profile.rs#L678), [`core/dr-gpu/src/adjust.rs:37`](../../core/dr-gpu/src/adjust.rs#L37), [`core/dr-gpu/src/adjust.rs:995`](../../core/dr-gpu/src/adjust.rs#L995), [`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:1985`](../../core/dr-pipeline/src/operation.rs#L1985), [`core/dr-pipeline/src/operation.rs:2066`](../../core/dr-pipeline/src/operation.rs#L2066), [`core/dr-pipeline/src/operation.rs:2091`](../../core/dr-pipeline/src/operation.rs#L2091), [`core/dr-pipeline/src/operation.rs:2106`](../../core/dr-pipeline/src/operation.rs#L2106), [`core/dr-pipeline/src/operation.rs:2130`](../../core/dr-pipeline/src/operation.rs#L2130), [`core/dr-pipeline/src/operation.rs:310`](../../core/dr-pipeline/src/operation.rs#L310), [`core/dr-pipeline/src/operation.rs:471`](../../core/dr-pipeline/src/operation.rs#L471), [`core/dr-pipeline/src/operation.rs:481`](../../core/dr-pipeline/src/operation.rs#L481), [`core/dr-pipeline/src/operation.rs:769`](../../core/dr-pipeline/src/operation.rs#L769) |
-| 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:149`](../../core/dr-gpu/src/adjust.rs#L149), [`core/dr-gpu/src/adjust.rs:206`](../../core/dr-gpu/src/adjust.rs#L206), [`core/dr-gpu/src/adjust.rs:381`](../../core/dr-gpu/src/adjust.rs#L381), [`core/dr-gpu/src/adjust.rs:510`](../../core/dr-gpu/src/adjust.rs#L510), [`core/dr-gpu/src/adjust.rs:77`](../../core/dr-gpu/src/adjust.rs#L77), [`core/dr-gpu/tests/film_sim.rs:195`](../../core/dr-gpu/tests/film_sim.rs#L195), [`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:168`](../../core/dr-pipeline/src/graph.rs#L168), [`core/dr-pipeline/src/graph.rs:566`](../../core/dr-pipeline/src/graph.rs#L566), [`core/dr-pipeline/src/operation.rs:1313`](../../core/dr-pipeline/src/operation.rs#L1313), [`core/dr-pipeline/src/operation.rs:1341`](../../core/dr-pipeline/src/operation.rs#L1341), [`core/dr-pipeline/src/operation.rs:1387`](../../core/dr-pipeline/src/operation.rs#L1387), [`core/dr-pipeline/src/operation.rs:1985`](../../core/dr-pipeline/src/operation.rs#L1985), [`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:1055`](../../core/dr-pipeline/src/sidecar.rs#L1055), [`core/dr-pipeline/src/sidecar.rs:130`](../../core/dr-pipeline/src/sidecar.rs#L130), [`core/dr-pipeline/src/sidecar.rs:203`](../../core/dr-pipeline/src/sidecar.rs#L203), [`core/dr-pipeline/src/sidecar.rs:2681`](../../core/dr-pipeline/src/sidecar.rs#L2681), [`core/dr-pipeline/src/sidecar.rs:2757`](../../core/dr-pipeline/src/sidecar.rs#L2757), [`core/dr-pipeline/src/sidecar.rs:576`](../../core/dr-pipeline/src/sidecar.rs#L576), [`core/dr-pipeline/src/sidecar.rs:876`](../../core/dr-pipeline/src/sidecar.rs#L876), [`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/render.rs:1051`](../../ui/dr-ui/src/develop/render.rs#L1051), [`ui/dr-ui/src/develop/render.rs:642`](../../ui/dr-ui/src/develop/render.rs#L642), [`ui/dr-ui/src/develop/render.rs:659`](../../ui/dr-ui/src/develop/render.rs#L659), [`ui/dr-ui/src/develop/render.rs:671`](../../ui/dr-ui/src/develop/render.rs#L671), [`ui/dr-ui/src/develop/render.rs:709`](../../ui/dr-ui/src/develop/render.rs#L709), [`ui/dr-ui/src/develop/render.rs:718`](../../ui/dr-ui/src/develop/render.rs#L718), [`ui/dr-ui/src/develop/render.rs:821`](../../ui/dr-ui/src/develop/render.rs#L821), [`ui/dr-ui/src/develop/render.rs:847`](../../ui/dr-ui/src/develop/render.rs#L847), [`ui/dr-ui/src/develop/session.rs:598`](../../ui/dr-ui/src/develop/session.rs#L598), [`ui/dr-ui/src/develop/tabs.rs:80`](../../ui/dr-ui/src/develop/tabs.rs#L80), [`ui/dr-ui/src/develop_ui.rs:378`](../../ui/dr-ui/src/develop_ui.rs#L378), [`ui/dr-ui/src/lib.rs:806`](../../ui/dr-ui/src/lib.rs#L806), [`ui/dr-ui/src/lib.rs:871`](../../ui/dr-ui/src/lib.rs#L871), [`ui/dr-ui/src/library/sidecar.rs:317`](../../ui/dr-ui/src/library/sidecar.rs#L317), [`ui/dr-ui/src/library/sidecar.rs:49`](../../ui/dr-ui/src/library/sidecar.rs#L49), [`ui/dr-ui/src/presets.rs:422`](../../ui/dr-ui/src/presets.rs#L422), [`ui/dr-ui/ui/adjust.slint:1040`](../../ui/dr-ui/ui/adjust.slint#L1040), [`ui/dr-ui/ui/adjust.slint:1050`](../../ui/dr-ui/ui/adjust.slint#L1050), [`ui/dr-ui/ui/adjust.slint:1268`](../../ui/dr-ui/ui/adjust.slint#L1268) |
+| 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:149`](../../core/dr-gpu/src/adjust.rs#L149), [`core/dr-gpu/src/adjust.rs:206`](../../core/dr-gpu/src/adjust.rs#L206), [`core/dr-gpu/src/adjust.rs:381`](../../core/dr-gpu/src/adjust.rs#L381), [`core/dr-gpu/src/adjust.rs:510`](../../core/dr-gpu/src/adjust.rs#L510), [`core/dr-gpu/src/adjust.rs:77`](../../core/dr-gpu/src/adjust.rs#L77), [`core/dr-gpu/tests/film_sim.rs:195`](../../core/dr-gpu/tests/film_sim.rs#L195), [`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:168`](../../core/dr-pipeline/src/graph.rs#L168), [`core/dr-pipeline/src/graph.rs:566`](../../core/dr-pipeline/src/graph.rs#L566), [`core/dr-pipeline/src/operation.rs:1313`](../../core/dr-pipeline/src/operation.rs#L1313), [`core/dr-pipeline/src/operation.rs:1341`](../../core/dr-pipeline/src/operation.rs#L1341), [`core/dr-pipeline/src/operation.rs:1387`](../../core/dr-pipeline/src/operation.rs#L1387), [`core/dr-pipeline/src/operation.rs:1985`](../../core/dr-pipeline/src/operation.rs#L1985), [`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:1055`](../../core/dr-pipeline/src/sidecar.rs#L1055), [`core/dr-pipeline/src/sidecar.rs:130`](../../core/dr-pipeline/src/sidecar.rs#L130), [`core/dr-pipeline/src/sidecar.rs:203`](../../core/dr-pipeline/src/sidecar.rs#L203), [`core/dr-pipeline/src/sidecar.rs:2681`](../../core/dr-pipeline/src/sidecar.rs#L2681), [`core/dr-pipeline/src/sidecar.rs:2757`](../../core/dr-pipeline/src/sidecar.rs#L2757), [`core/dr-pipeline/src/sidecar.rs:576`](../../core/dr-pipeline/src/sidecar.rs#L576), [`core/dr-pipeline/src/sidecar.rs:876`](../../core/dr-pipeline/src/sidecar.rs#L876), [`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/render.rs:1051`](../../ui/dr-ui/src/develop/render.rs#L1051), [`ui/dr-ui/src/develop/render.rs:642`](../../ui/dr-ui/src/develop/render.rs#L642), [`ui/dr-ui/src/develop/render.rs:659`](../../ui/dr-ui/src/develop/render.rs#L659), [`ui/dr-ui/src/develop/render.rs:671`](../../ui/dr-ui/src/develop/render.rs#L671), [`ui/dr-ui/src/develop/render.rs:709`](../../ui/dr-ui/src/develop/render.rs#L709), [`ui/dr-ui/src/develop/render.rs:718`](../../ui/dr-ui/src/develop/render.rs#L718), [`ui/dr-ui/src/develop/render.rs:821`](../../ui/dr-ui/src/develop/render.rs#L821), [`ui/dr-ui/src/develop/render.rs:847`](../../ui/dr-ui/src/develop/render.rs#L847), [`ui/dr-ui/src/develop/session.rs:598`](../../ui/dr-ui/src/develop/session.rs#L598), [`ui/dr-ui/src/develop/tabs.rs:80`](../../ui/dr-ui/src/develop/tabs.rs#L80), [`ui/dr-ui/src/develop_ui.rs:386`](../../ui/dr-ui/src/develop_ui.rs#L386), [`ui/dr-ui/src/lib.rs:807`](../../ui/dr-ui/src/lib.rs#L807), [`ui/dr-ui/src/lib.rs:872`](../../ui/dr-ui/src/lib.rs#L872), [`ui/dr-ui/src/library/sidecar.rs:317`](../../ui/dr-ui/src/library/sidecar.rs#L317), [`ui/dr-ui/src/library/sidecar.rs:49`](../../ui/dr-ui/src/library/sidecar.rs#L49), [`ui/dr-ui/src/presets.rs:422`](../../ui/dr-ui/src/presets.rs#L422), [`ui/dr-ui/ui/adjust.slint:1040`](../../ui/dr-ui/ui/adjust.slint#L1040), [`ui/dr-ui/ui/adjust.slint:1050`](../../ui/dr-ui/ui/adjust.slint#L1050), [`ui/dr-ui/ui/adjust.slint:1268`](../../ui/dr-ui/ui/adjust.slint#L1268) |
| FR-DEV-3h | [`core/dr-decode/src/lib.rs:444`](../../core/dr-decode/src/lib.rs#L444), [`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/masks.rs:279`](../../ui/dr-ui/src/develop/masks.rs#L279), [`ui/dr-ui/src/develop/segmentation.rs:114`](../../ui/dr-ui/src/develop/segmentation.rs#L114), [`ui/dr-ui/src/segmentation.rs:499`](../../ui/dr-ui/src/segmentation.rs#L499) |
| FR-DEV-3i | [`core/dr-pipeline/src/mask.rs:558`](../../core/dr-pipeline/src/mask.rs#L558), [`core/dr-segment/src/lib.rs:1`](../../core/dr-segment/src/lib.rs#L1), [`ui/dr-ui/src/segmentation.rs:1`](../../ui/dr-ui/src/segmentation.rs#L1) |
| FR-DEV-4 | [`core/dr-gpu/src/adjust.rs:798`](../../core/dr-gpu/src/adjust.rs#L798), [`core/dr-gpu/src/lib.rs:368`](../../core/dr-gpu/src/lib.rs#L368), [`ui/dr-ui/ui/crop.slint:1`](../../ui/dr-ui/ui/crop.slint#L1) |
-| FR-DEV-5 | [`core/dr-pipeline/src/graph.rs:1440`](../../core/dr-pipeline/src/graph.rs#L1440), [`core/dr-pipeline/src/graph.rs:587`](../../core/dr-pipeline/src/graph.rs#L587), [`core/dr-pipeline/src/graph.rs:640`](../../core/dr-pipeline/src/graph.rs#L640), [`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/sidecar.rs:1045`](../../core/dr-pipeline/src/sidecar.rs#L1045), [`core/dr-pipeline/src/sidecar.rs:144`](../../core/dr-pipeline/src/sidecar.rs#L144), [`core/dr-pipeline/src/sidecar.rs:2472`](../../core/dr-pipeline/src/sidecar.rs#L2472), [`core/dr-pipeline/src/sidecar.rs:2508`](../../core/dr-pipeline/src/sidecar.rs#L2508), [`core/dr-pipeline/src/sidecar.rs:2520`](../../core/dr-pipeline/src/sidecar.rs#L2520), [`core/dr-pipeline/src/sidecar.rs:303`](../../core/dr-pipeline/src/sidecar.rs#L303), [`core/dr-pipeline/src/sidecar.rs:694`](../../core/dr-pipeline/src/sidecar.rs#L694), [`core/dr-pipeline/src/sidecar.rs:710`](../../core/dr-pipeline/src/sidecar.rs#L710), [`core/dr-pipeline/src/sidecar.rs:857`](../../core/dr-pipeline/src/sidecar.rs#L857), [`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/framing.rs:720`](../../ui/dr-ui/src/develop/framing.rs#L720), [`ui/dr-ui/src/develop/history.rs:11`](../../ui/dr-ui/src/develop/history.rs#L11), [`ui/dr-ui/src/develop/history.rs:152`](../../ui/dr-ui/src/develop/history.rs#L152), [`ui/dr-ui/src/develop/history.rs:165`](../../ui/dr-ui/src/develop/history.rs#L165), [`ui/dr-ui/src/develop/history.rs:178`](../../ui/dr-ui/src/develop/history.rs#L178), [`ui/dr-ui/src/develop/history.rs:190`](../../ui/dr-ui/src/develop/history.rs#L190), [`ui/dr-ui/src/develop/history.rs:206`](../../ui/dr-ui/src/develop/history.rs#L206), [`ui/dr-ui/src/develop/history.rs:238`](../../ui/dr-ui/src/develop/history.rs#L238), [`ui/dr-ui/src/develop/history.rs:242`](../../ui/dr-ui/src/develop/history.rs#L242), [`ui/dr-ui/src/develop/history.rs:261`](../../ui/dr-ui/src/develop/history.rs#L261), [`ui/dr-ui/src/develop/history.rs:277`](../../ui/dr-ui/src/develop/history.rs#L277), [`ui/dr-ui/src/develop/history.rs:299`](../../ui/dr-ui/src/develop/history.rs#L299), [`ui/dr-ui/src/develop/history.rs:29`](../../ui/dr-ui/src/develop/history.rs#L29), [`ui/dr-ui/src/develop/history.rs:359`](../../ui/dr-ui/src/develop/history.rs#L359), [`ui/dr-ui/src/develop/history.rs:68`](../../ui/dr-ui/src/develop/history.rs#L68), [`ui/dr-ui/src/develop/history.rs:82`](../../ui/dr-ui/src/develop/history.rs#L82), [`ui/dr-ui/src/develop/history.rs:93`](../../ui/dr-ui/src/develop/history.rs#L93), [`ui/dr-ui/src/develop/render.rs:671`](../../ui/dr-ui/src/develop/render.rs#L671), [`ui/dr-ui/src/develop/render.rs:847`](../../ui/dr-ui/src/develop/render.rs#L847), [`ui/dr-ui/src/develop/render.rs:883`](../../ui/dr-ui/src/develop/render.rs#L883), [`ui/dr-ui/src/develop/session.rs:80`](../../ui/dr-ui/src/develop/session.rs#L80), [`ui/dr-ui/src/develop/session.rs:89`](../../ui/dr-ui/src/develop/session.rs#L89), [`ui/dr-ui/src/develop/white_balance.rs:11`](../../ui/dr-ui/src/develop/white_balance.rs#L11), [`ui/dr-ui/src/develop/white_balance.rs:162`](../../ui/dr-ui/src/develop/white_balance.rs#L162), [`ui/dr-ui/src/develop_ui.rs:657`](../../ui/dr-ui/src/develop_ui.rs#L657), [`ui/dr-ui/src/develop_ui.rs:677`](../../ui/dr-ui/src/develop_ui.rs#L677), [`ui/dr-ui/src/labels.rs:12`](../../ui/dr-ui/src/labels.rs#L12), [`ui/dr-ui/src/labels.rs:278`](../../ui/dr-ui/src/labels.rs#L278), [`ui/dr-ui/src/labels.rs:31`](../../ui/dr-ui/src/labels.rs#L31), [`ui/dr-ui/src/lib.rs:2123`](../../ui/dr-ui/src/lib.rs#L2123), [`ui/dr-ui/src/lib.rs:2128`](../../ui/dr-ui/src/lib.rs#L2128), [`ui/dr-ui/src/lib.rs:2160`](../../ui/dr-ui/src/lib.rs#L2160), [`ui/dr-ui/src/lib.rs:2169`](../../ui/dr-ui/src/lib.rs#L2169), [`ui/dr-ui/src/lib.rs:2181`](../../ui/dr-ui/src/lib.rs#L2181), [`ui/dr-ui/src/library/sidecar.rs:343`](../../ui/dr-ui/src/library/sidecar.rs#L343), [`ui/dr-ui/src/library/sidecar.rs:58`](../../ui/dr-ui/src/library/sidecar.rs#L58), [`ui/dr-ui/src/presets.rs:1678`](../../ui/dr-ui/src/presets.rs#L1678), [`ui/dr-ui/src/presets.rs:373`](../../ui/dr-ui/src/presets.rs#L373), [`ui/dr-ui/src/presets.rs:437`](../../ui/dr-ui/src/presets.rs#L437), [`ui/dr-ui/src/presets.rs:557`](../../ui/dr-ui/src/presets.rs#L557), [`ui/dr-ui/ui/history.slint:191`](../../ui/dr-ui/ui/history.slint#L191), [`ui/dr-ui/ui/history.slint:1`](../../ui/dr-ui/ui/history.slint#L1), [`ui/dr-ui/ui/history.slint:218`](../../ui/dr-ui/ui/history.slint#L218), [`ui/dr-ui/ui/history.slint:303`](../../ui/dr-ui/ui/history.slint#L303), [`ui/dr-ui/ui/history.slint:43`](../../ui/dr-ui/ui/history.slint#L43), [`ui/dr-ui/ui/history.slint:53`](../../ui/dr-ui/ui/history.slint#L53) |
-| FR-DEV-6 | [`core/dr-pipeline/src/preset.rs:1`](../../core/dr-pipeline/src/preset.rs#L1), [`core/dr-pipeline/src/preset.rs:390`](../../core/dr-pipeline/src/preset.rs#L390), [`core/dr-pipeline/src/preset.rs:423`](../../core/dr-pipeline/src/preset.rs#L423), [`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:443`](../../core/dr-types/src/settings.rs#L443), [`ui/dr-ui/src/develop/session.rs:555`](../../ui/dr-ui/src/develop/session.rs#L555), [`ui/dr-ui/src/develop/session.rs:576`](../../ui/dr-ui/src/develop/session.rs#L576), [`ui/dr-ui/src/develop_ui.rs:167`](../../ui/dr-ui/src/develop_ui.rs#L167), [`ui/dr-ui/src/develop_ui.rs:196`](../../ui/dr-ui/src/develop_ui.rs#L196), [`ui/dr-ui/src/lib.rs:1243`](../../ui/dr-ui/src/lib.rs#L1243), [`ui/dr-ui/src/library/sidecar.rs:11`](../../ui/dr-ui/src/library/sidecar.rs#L11), [`ui/dr-ui/src/library/sidecar.rs:39`](../../ui/dr-ui/src/library/sidecar.rs#L39), [`ui/dr-ui/src/library/thumbnails_fetch.rs:413`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L413), [`ui/dr-ui/src/library_ui/controller.rs:625`](../../ui/dr-ui/src/library_ui/controller.rs#L625), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:331`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L331), [`ui/dr-ui/src/library_ui/window.rs:545`](../../ui/dr-ui/src/library_ui/window.rs#L545), [`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:707`](../../ui/dr-ui/src/presets.rs#L707), [`ui/dr-ui/src/presets.rs:741`](../../ui/dr-ui/src/presets.rs#L741), [`ui/dr-ui/ui/adjust.slint:853`](../../ui/dr-ui/ui/adjust.slint#L853), [`ui/dr-ui/ui/adjust.slint:878`](../../ui/dr-ui/ui/adjust.slint#L878), [`ui/dr-ui/ui/adjust.slint:889`](../../ui/dr-ui/ui/adjust.slint#L889), [`ui/dr-ui/ui/adjust.slint:932`](../../ui/dr-ui/ui/adjust.slint#L932), [`ui/dr-ui/ui/app.slint:1662`](../../ui/dr-ui/ui/app.slint#L1662), [`ui/dr-ui/ui/app.slint:2494`](../../ui/dr-ui/ui/app.slint#L2494), [`ui/dr-ui/ui/app.slint:3129`](../../ui/dr-ui/ui/app.slint#L3129), [`ui/dr-ui/ui/app.slint:723`](../../ui/dr-ui/ui/app.slint#L723), [`ui/dr-ui/ui/app.slint:734`](../../ui/dr-ui/ui/app.slint#L734), [`ui/dr-ui/ui/library.slint:1579`](../../ui/dr-ui/ui/library.slint#L1579), [`ui/dr-ui/ui/library.slint:1585`](../../ui/dr-ui/ui/library.slint#L1585), [`ui/dr-ui/ui/library.slint:4269`](../../ui/dr-ui/ui/library.slint#L4269), [`ui/dr-ui/ui/library.slint:4293`](../../ui/dr-ui/ui/library.slint#L4293), [`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:119`](../../ui/dr-ui/ui/settings.slint#L119), [`ui/dr-ui/ui/settings.slint:711`](../../ui/dr-ui/ui/settings.slint#L711) |
-| 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/history.rs:107`](../../ui/dr-ui/src/develop/history.rs#L107), [`ui/dr-ui/src/develop/history.rs:124`](../../ui/dr-ui/src/develop/history.rs#L124), [`ui/dr-ui/src/develop/history.rs:206`](../../ui/dr-ui/src/develop/history.rs#L206), [`ui/dr-ui/src/develop/history.rs:238`](../../ui/dr-ui/src/develop/history.rs#L238), [`ui/dr-ui/src/develop/history.rs:359`](../../ui/dr-ui/src/develop/history.rs#L359), [`ui/dr-ui/src/develop/render.rs:453`](../../ui/dr-ui/src/develop/render.rs#L453), [`ui/dr-ui/src/develop/render.rs:494`](../../ui/dr-ui/src/develop/render.rs#L494), [`ui/dr-ui/src/develop/render.rs:883`](../../ui/dr-ui/src/develop/render.rs#L883), [`ui/dr-ui/src/develop/session.rs:105`](../../ui/dr-ui/src/develop/session.rs#L105), [`ui/dr-ui/src/develop_ui.rs:598`](../../ui/dr-ui/src/develop_ui.rs#L598), [`ui/dr-ui/src/develop_ui.rs:657`](../../ui/dr-ui/src/develop_ui.rs#L657), [`ui/dr-ui/src/develop_ui.rs:729`](../../ui/dr-ui/src/develop_ui.rs#L729), [`ui/dr-ui/src/lib.rs:2169`](../../ui/dr-ui/src/lib.rs#L2169), [`ui/dr-ui/src/lib.rs:2241`](../../ui/dr-ui/src/lib.rs#L2241), [`ui/dr-ui/src/lib.rs:2255`](../../ui/dr-ui/src/lib.rs#L2255), [`ui/dr-ui/src/lib.rs:412`](../../ui/dr-ui/src/lib.rs#L412), [`ui/dr-ui/ui/app.slint:171`](../../ui/dr-ui/ui/app.slint#L171), [`ui/dr-ui/ui/app.slint:2401`](../../ui/dr-ui/ui/app.slint#L2401), [`ui/dr-ui/ui/app.slint:2416`](../../ui/dr-ui/ui/app.slint#L2416), [`ui/dr-ui/ui/app.slint:2736`](../../ui/dr-ui/ui/app.slint#L2736), [`ui/dr-ui/ui/history.slint:102`](../../ui/dr-ui/ui/history.slint#L102), [`ui/dr-ui/ui/history.slint:1`](../../ui/dr-ui/ui/history.slint#L1), [`ui/dr-ui/ui/history.slint:226`](../../ui/dr-ui/ui/history.slint#L226), [`ui/dr-ui/ui/history.slint:53`](../../ui/dr-ui/ui/history.slint#L53), [`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:1092`](../../core/dr-pipeline/src/graph.rs#L1092), [`core/dr-pipeline/src/graph.rs:115`](../../core/dr-pipeline/src/graph.rs#L115), [`core/dr-pipeline/src/graph.rs:247`](../../core/dr-pipeline/src/graph.rs#L247), [`core/dr-pipeline/src/operation.rs:330`](../../core/dr-pipeline/src/operation.rs#L330), [`core/dr-pipeline/src/operation.rs:717`](../../core/dr-pipeline/src/operation.rs#L717), [`core/dr-pipeline/src/sidecar.rs:1071`](../../core/dr-pipeline/src/sidecar.rs#L1071), [`core/dr-pipeline/src/sidecar.rs:1125`](../../core/dr-pipeline/src/sidecar.rs#L1125), [`core/dr-pipeline/src/sidecar.rs:1155`](../../core/dr-pipeline/src/sidecar.rs#L1155), [`core/dr-pipeline/src/sidecar.rs:219`](../../core/dr-pipeline/src/sidecar.rs#L219), [`core/dr-pipeline/src/sidecar.rs:395`](../../core/dr-pipeline/src/sidecar.rs#L395), [`core/dr-pipeline/src/sidecar.rs:888`](../../core/dr-pipeline/src/sidecar.rs#L888), [`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/repairs.rs:114`](../../ui/dr-ui/src/develop/repairs.rs#L114), [`ui/dr-ui/src/develop/repairs.rs:11`](../../ui/dr-ui/src/develop/repairs.rs#L11), [`ui/dr-ui/src/develop/repairs.rs:197`](../../ui/dr-ui/src/develop/repairs.rs#L197), [`ui/dr-ui/src/develop/repairs.rs:211`](../../ui/dr-ui/src/develop/repairs.rs#L211), [`ui/dr-ui/src/develop/repairs.rs:49`](../../ui/dr-ui/src/develop/repairs.rs#L49), [`ui/dr-ui/src/develop/session.rs:212`](../../ui/dr-ui/src/develop/session.rs#L212), [`ui/dr-ui/src/develop_ui.rs:884`](../../ui/dr-ui/src/develop_ui.rs#L884), [`ui/dr-ui/src/labels.rs:80`](../../ui/dr-ui/src/labels.rs#L80), [`ui/dr-ui/src/lib.rs:2199`](../../ui/dr-ui/src/lib.rs#L2199), [`ui/dr-ui/src/lib.rs:454`](../../ui/dr-ui/src/lib.rs#L454), [`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:2257`](../../ui/dr-ui/ui/app.slint#L2257), [`ui/dr-ui/ui/app.slint:2459`](../../ui/dr-ui/ui/app.slint#L2459), [`ui/dr-ui/ui/app.slint:3035`](../../ui/dr-ui/ui/app.slint#L3035), [`ui/dr-ui/ui/icons.slint:366`](../../ui/dr-ui/ui/icons.slint#L366), [`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:2366`](../../core/dr-gpu/src/adjust.rs#L2366), [`core/dr-gpu/src/adjust.rs:2443`](../../core/dr-gpu/src/adjust.rs#L2443), [`core/dr-gpu/src/adjust.rs:2528`](../../core/dr-gpu/src/adjust.rs#L2528), [`core/dr-gpu/src/adjust.rs:54`](../../core/dr-gpu/src/adjust.rs#L54), [`core/dr-gpu/src/adjust.rs:798`](../../core/dr-gpu/src/adjust.rs#L798), [`core/dr-gpu/src/lib.rs:174`](../../core/dr-gpu/src/lib.rs#L174), [`core/dr-gpu/src/lib.rs:194`](../../core/dr-gpu/src/lib.rs#L194), [`core/dr-gpu/src/lib.rs:72`](../../core/dr-gpu/src/lib.rs#L72), [`core/dr-gpu/src/lib.rs:95`](../../core/dr-gpu/src/lib.rs#L95), [`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:922`](../../core/dr-pipeline/src/graph.rs#L922), [`core/dr-pipeline/src/graph.rs:952`](../../core/dr-pipeline/src/graph.rs#L952), [`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/framing.rs:444`](../../ui/dr-ui/src/develop/framing.rs#L444), [`ui/dr-ui/src/develop/mod.rs:55`](../../ui/dr-ui/src/develop/mod.rs#L55), [`ui/dr-ui/src/develop/render.rs:140`](../../ui/dr-ui/src/develop/render.rs#L140), [`ui/dr-ui/src/develop/render.rs:940`](../../ui/dr-ui/src/develop/render.rs#L940), [`ui/dr-ui/src/develop/render.rs:974`](../../ui/dr-ui/src/develop/render.rs#L974), [`ui/dr-ui/src/lib.rs:101`](../../ui/dr-ui/src/lib.rs#L101), [`ui/dr-ui/src/lib.rs:1027`](../../ui/dr-ui/src/lib.rs#L1027), [`ui/dr-ui/src/lib.rs:1086`](../../ui/dr-ui/src/lib.rs#L1086) |
+| FR-DEV-5 | [`core/dr-pipeline/src/graph.rs:1440`](../../core/dr-pipeline/src/graph.rs#L1440), [`core/dr-pipeline/src/graph.rs:587`](../../core/dr-pipeline/src/graph.rs#L587), [`core/dr-pipeline/src/graph.rs:640`](../../core/dr-pipeline/src/graph.rs#L640), [`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/sidecar.rs:1045`](../../core/dr-pipeline/src/sidecar.rs#L1045), [`core/dr-pipeline/src/sidecar.rs:144`](../../core/dr-pipeline/src/sidecar.rs#L144), [`core/dr-pipeline/src/sidecar.rs:2472`](../../core/dr-pipeline/src/sidecar.rs#L2472), [`core/dr-pipeline/src/sidecar.rs:2508`](../../core/dr-pipeline/src/sidecar.rs#L2508), [`core/dr-pipeline/src/sidecar.rs:2520`](../../core/dr-pipeline/src/sidecar.rs#L2520), [`core/dr-pipeline/src/sidecar.rs:303`](../../core/dr-pipeline/src/sidecar.rs#L303), [`core/dr-pipeline/src/sidecar.rs:694`](../../core/dr-pipeline/src/sidecar.rs#L694), [`core/dr-pipeline/src/sidecar.rs:710`](../../core/dr-pipeline/src/sidecar.rs#L710), [`core/dr-pipeline/src/sidecar.rs:857`](../../core/dr-pipeline/src/sidecar.rs#L857), [`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/framing.rs:720`](../../ui/dr-ui/src/develop/framing.rs#L720), [`ui/dr-ui/src/develop/history.rs:11`](../../ui/dr-ui/src/develop/history.rs#L11), [`ui/dr-ui/src/develop/history.rs:152`](../../ui/dr-ui/src/develop/history.rs#L152), [`ui/dr-ui/src/develop/history.rs:165`](../../ui/dr-ui/src/develop/history.rs#L165), [`ui/dr-ui/src/develop/history.rs:178`](../../ui/dr-ui/src/develop/history.rs#L178), [`ui/dr-ui/src/develop/history.rs:190`](../../ui/dr-ui/src/develop/history.rs#L190), [`ui/dr-ui/src/develop/history.rs:206`](../../ui/dr-ui/src/develop/history.rs#L206), [`ui/dr-ui/src/develop/history.rs:238`](../../ui/dr-ui/src/develop/history.rs#L238), [`ui/dr-ui/src/develop/history.rs:242`](../../ui/dr-ui/src/develop/history.rs#L242), [`ui/dr-ui/src/develop/history.rs:261`](../../ui/dr-ui/src/develop/history.rs#L261), [`ui/dr-ui/src/develop/history.rs:277`](../../ui/dr-ui/src/develop/history.rs#L277), [`ui/dr-ui/src/develop/history.rs:299`](../../ui/dr-ui/src/develop/history.rs#L299), [`ui/dr-ui/src/develop/history.rs:29`](../../ui/dr-ui/src/develop/history.rs#L29), [`ui/dr-ui/src/develop/history.rs:359`](../../ui/dr-ui/src/develop/history.rs#L359), [`ui/dr-ui/src/develop/history.rs:68`](../../ui/dr-ui/src/develop/history.rs#L68), [`ui/dr-ui/src/develop/history.rs:82`](../../ui/dr-ui/src/develop/history.rs#L82), [`ui/dr-ui/src/develop/history.rs:93`](../../ui/dr-ui/src/develop/history.rs#L93), [`ui/dr-ui/src/develop/render.rs:671`](../../ui/dr-ui/src/develop/render.rs#L671), [`ui/dr-ui/src/develop/render.rs:847`](../../ui/dr-ui/src/develop/render.rs#L847), [`ui/dr-ui/src/develop/render.rs:883`](../../ui/dr-ui/src/develop/render.rs#L883), [`ui/dr-ui/src/develop/session.rs:80`](../../ui/dr-ui/src/develop/session.rs#L80), [`ui/dr-ui/src/develop/session.rs:89`](../../ui/dr-ui/src/develop/session.rs#L89), [`ui/dr-ui/src/develop/white_balance.rs:11`](../../ui/dr-ui/src/develop/white_balance.rs#L11), [`ui/dr-ui/src/develop/white_balance.rs:162`](../../ui/dr-ui/src/develop/white_balance.rs#L162), [`ui/dr-ui/src/develop_ui.rs:665`](../../ui/dr-ui/src/develop_ui.rs#L665), [`ui/dr-ui/src/develop_ui.rs:685`](../../ui/dr-ui/src/develop_ui.rs#L685), [`ui/dr-ui/src/labels.rs:12`](../../ui/dr-ui/src/labels.rs#L12), [`ui/dr-ui/src/labels.rs:278`](../../ui/dr-ui/src/labels.rs#L278), [`ui/dr-ui/src/labels.rs:31`](../../ui/dr-ui/src/labels.rs#L31), [`ui/dr-ui/src/lib.rs:2124`](../../ui/dr-ui/src/lib.rs#L2124), [`ui/dr-ui/src/lib.rs:2129`](../../ui/dr-ui/src/lib.rs#L2129), [`ui/dr-ui/src/lib.rs:2161`](../../ui/dr-ui/src/lib.rs#L2161), [`ui/dr-ui/src/lib.rs:2170`](../../ui/dr-ui/src/lib.rs#L2170), [`ui/dr-ui/src/lib.rs:2182`](../../ui/dr-ui/src/lib.rs#L2182), [`ui/dr-ui/src/library/sidecar.rs:343`](../../ui/dr-ui/src/library/sidecar.rs#L343), [`ui/dr-ui/src/library/sidecar.rs:58`](../../ui/dr-ui/src/library/sidecar.rs#L58), [`ui/dr-ui/src/presets.rs:1678`](../../ui/dr-ui/src/presets.rs#L1678), [`ui/dr-ui/src/presets.rs:373`](../../ui/dr-ui/src/presets.rs#L373), [`ui/dr-ui/src/presets.rs:437`](../../ui/dr-ui/src/presets.rs#L437), [`ui/dr-ui/src/presets.rs:557`](../../ui/dr-ui/src/presets.rs#L557), [`ui/dr-ui/ui/history.slint:191`](../../ui/dr-ui/ui/history.slint#L191), [`ui/dr-ui/ui/history.slint:1`](../../ui/dr-ui/ui/history.slint#L1), [`ui/dr-ui/ui/history.slint:218`](../../ui/dr-ui/ui/history.slint#L218), [`ui/dr-ui/ui/history.slint:303`](../../ui/dr-ui/ui/history.slint#L303), [`ui/dr-ui/ui/history.slint:43`](../../ui/dr-ui/ui/history.slint#L43), [`ui/dr-ui/ui/history.slint:53`](../../ui/dr-ui/ui/history.slint#L53) |
+| FR-DEV-6 | [`core/dr-pipeline/src/preset.rs:1`](../../core/dr-pipeline/src/preset.rs#L1), [`core/dr-pipeline/src/preset.rs:390`](../../core/dr-pipeline/src/preset.rs#L390), [`core/dr-pipeline/src/preset.rs:423`](../../core/dr-pipeline/src/preset.rs#L423), [`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:443`](../../core/dr-types/src/settings.rs#L443), [`ui/dr-ui/src/develop/session.rs:555`](../../ui/dr-ui/src/develop/session.rs#L555), [`ui/dr-ui/src/develop/session.rs:576`](../../ui/dr-ui/src/develop/session.rs#L576), [`ui/dr-ui/src/develop_ui.rs:167`](../../ui/dr-ui/src/develop_ui.rs#L167), [`ui/dr-ui/src/develop_ui.rs:196`](../../ui/dr-ui/src/develop_ui.rs#L196), [`ui/dr-ui/src/lib.rs:1244`](../../ui/dr-ui/src/lib.rs#L1244), [`ui/dr-ui/src/library/sidecar.rs:11`](../../ui/dr-ui/src/library/sidecar.rs#L11), [`ui/dr-ui/src/library/sidecar.rs:39`](../../ui/dr-ui/src/library/sidecar.rs#L39), [`ui/dr-ui/src/library/thumbnails_fetch.rs:413`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L413), [`ui/dr-ui/src/library_ui/controller.rs:625`](../../ui/dr-ui/src/library_ui/controller.rs#L625), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:353`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L353), [`ui/dr-ui/src/library_ui/window.rs:551`](../../ui/dr-ui/src/library_ui/window.rs#L551), [`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:707`](../../ui/dr-ui/src/presets.rs#L707), [`ui/dr-ui/src/presets.rs:741`](../../ui/dr-ui/src/presets.rs#L741), [`ui/dr-ui/ui/adjust.slint:853`](../../ui/dr-ui/ui/adjust.slint#L853), [`ui/dr-ui/ui/adjust.slint:878`](../../ui/dr-ui/ui/adjust.slint#L878), [`ui/dr-ui/ui/adjust.slint:889`](../../ui/dr-ui/ui/adjust.slint#L889), [`ui/dr-ui/ui/adjust.slint:932`](../../ui/dr-ui/ui/adjust.slint#L932), [`ui/dr-ui/ui/app.slint:1398`](../../ui/dr-ui/ui/app.slint#L1398), [`ui/dr-ui/ui/app.slint:2229`](../../ui/dr-ui/ui/app.slint#L2229), [`ui/dr-ui/ui/app.slint:2864`](../../ui/dr-ui/ui/app.slint#L2864), [`ui/dr-ui/ui/app.slint:468`](../../ui/dr-ui/ui/app.slint#L468), [`ui/dr-ui/ui/app.slint:479`](../../ui/dr-ui/ui/app.slint#L479), [`ui/dr-ui/ui/library.slint:1849`](../../ui/dr-ui/ui/library.slint#L1849), [`ui/dr-ui/ui/library.slint:1855`](../../ui/dr-ui/ui/library.slint#L1855), [`ui/dr-ui/ui/library.slint:4539`](../../ui/dr-ui/ui/library.slint#L4539), [`ui/dr-ui/ui/library.slint:4563`](../../ui/dr-ui/ui/library.slint#L4563), [`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:119`](../../ui/dr-ui/ui/settings.slint#L119), [`ui/dr-ui/ui/settings.slint:711`](../../ui/dr-ui/ui/settings.slint#L711) |
+| 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/history.rs:107`](../../ui/dr-ui/src/develop/history.rs#L107), [`ui/dr-ui/src/develop/history.rs:124`](../../ui/dr-ui/src/develop/history.rs#L124), [`ui/dr-ui/src/develop/history.rs:206`](../../ui/dr-ui/src/develop/history.rs#L206), [`ui/dr-ui/src/develop/history.rs:238`](../../ui/dr-ui/src/develop/history.rs#L238), [`ui/dr-ui/src/develop/history.rs:359`](../../ui/dr-ui/src/develop/history.rs#L359), [`ui/dr-ui/src/develop/render.rs:453`](../../ui/dr-ui/src/develop/render.rs#L453), [`ui/dr-ui/src/develop/render.rs:494`](../../ui/dr-ui/src/develop/render.rs#L494), [`ui/dr-ui/src/develop/render.rs:883`](../../ui/dr-ui/src/develop/render.rs#L883), [`ui/dr-ui/src/develop/session.rs:105`](../../ui/dr-ui/src/develop/session.rs#L105), [`ui/dr-ui/src/develop_ui.rs:606`](../../ui/dr-ui/src/develop_ui.rs#L606), [`ui/dr-ui/src/develop_ui.rs:665`](../../ui/dr-ui/src/develop_ui.rs#L665), [`ui/dr-ui/src/develop_ui.rs:737`](../../ui/dr-ui/src/develop_ui.rs#L737), [`ui/dr-ui/src/lib.rs:2170`](../../ui/dr-ui/src/lib.rs#L2170), [`ui/dr-ui/src/lib.rs:2242`](../../ui/dr-ui/src/lib.rs#L2242), [`ui/dr-ui/src/lib.rs:2256`](../../ui/dr-ui/src/lib.rs#L2256), [`ui/dr-ui/src/lib.rs:413`](../../ui/dr-ui/src/lib.rs#L413), [`ui/dr-ui/ui/app.slint:172`](../../ui/dr-ui/ui/app.slint#L172), [`ui/dr-ui/ui/app.slint:2136`](../../ui/dr-ui/ui/app.slint#L2136), [`ui/dr-ui/ui/app.slint:2151`](../../ui/dr-ui/ui/app.slint#L2151), [`ui/dr-ui/ui/app.slint:2471`](../../ui/dr-ui/ui/app.slint#L2471), [`ui/dr-ui/ui/history.slint:102`](../../ui/dr-ui/ui/history.slint#L102), [`ui/dr-ui/ui/history.slint:1`](../../ui/dr-ui/ui/history.slint#L1), [`ui/dr-ui/ui/history.slint:226`](../../ui/dr-ui/ui/history.slint#L226), [`ui/dr-ui/ui/history.slint:53`](../../ui/dr-ui/ui/history.slint#L53), [`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:1092`](../../core/dr-pipeline/src/graph.rs#L1092), [`core/dr-pipeline/src/graph.rs:115`](../../core/dr-pipeline/src/graph.rs#L115), [`core/dr-pipeline/src/graph.rs:247`](../../core/dr-pipeline/src/graph.rs#L247), [`core/dr-pipeline/src/operation.rs:330`](../../core/dr-pipeline/src/operation.rs#L330), [`core/dr-pipeline/src/operation.rs:717`](../../core/dr-pipeline/src/operation.rs#L717), [`core/dr-pipeline/src/sidecar.rs:1071`](../../core/dr-pipeline/src/sidecar.rs#L1071), [`core/dr-pipeline/src/sidecar.rs:1125`](../../core/dr-pipeline/src/sidecar.rs#L1125), [`core/dr-pipeline/src/sidecar.rs:1155`](../../core/dr-pipeline/src/sidecar.rs#L1155), [`core/dr-pipeline/src/sidecar.rs:219`](../../core/dr-pipeline/src/sidecar.rs#L219), [`core/dr-pipeline/src/sidecar.rs:395`](../../core/dr-pipeline/src/sidecar.rs#L395), [`core/dr-pipeline/src/sidecar.rs:888`](../../core/dr-pipeline/src/sidecar.rs#L888), [`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/repairs.rs:114`](../../ui/dr-ui/src/develop/repairs.rs#L114), [`ui/dr-ui/src/develop/repairs.rs:11`](../../ui/dr-ui/src/develop/repairs.rs#L11), [`ui/dr-ui/src/develop/repairs.rs:197`](../../ui/dr-ui/src/develop/repairs.rs#L197), [`ui/dr-ui/src/develop/repairs.rs:211`](../../ui/dr-ui/src/develop/repairs.rs#L211), [`ui/dr-ui/src/develop/repairs.rs:49`](../../ui/dr-ui/src/develop/repairs.rs#L49), [`ui/dr-ui/src/develop/session.rs:212`](../../ui/dr-ui/src/develop/session.rs#L212), [`ui/dr-ui/src/develop_ui.rs:892`](../../ui/dr-ui/src/develop_ui.rs#L892), [`ui/dr-ui/src/labels.rs:80`](../../ui/dr-ui/src/labels.rs#L80), [`ui/dr-ui/src/lib.rs:2200`](../../ui/dr-ui/src/lib.rs#L2200), [`ui/dr-ui/src/lib.rs:455`](../../ui/dr-ui/src/lib.rs#L455), [`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:1993`](../../ui/dr-ui/ui/app.slint#L1993), [`ui/dr-ui/ui/app.slint:2194`](../../ui/dr-ui/ui/app.slint#L2194), [`ui/dr-ui/ui/app.slint:2770`](../../ui/dr-ui/ui/app.slint#L2770), [`ui/dr-ui/ui/icons.slint:366`](../../ui/dr-ui/ui/icons.slint#L366), [`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:2366`](../../core/dr-gpu/src/adjust.rs#L2366), [`core/dr-gpu/src/adjust.rs:2443`](../../core/dr-gpu/src/adjust.rs#L2443), [`core/dr-gpu/src/adjust.rs:2528`](../../core/dr-gpu/src/adjust.rs#L2528), [`core/dr-gpu/src/adjust.rs:54`](../../core/dr-gpu/src/adjust.rs#L54), [`core/dr-gpu/src/adjust.rs:798`](../../core/dr-gpu/src/adjust.rs#L798), [`core/dr-gpu/src/lib.rs:174`](../../core/dr-gpu/src/lib.rs#L174), [`core/dr-gpu/src/lib.rs:194`](../../core/dr-gpu/src/lib.rs#L194), [`core/dr-gpu/src/lib.rs:72`](../../core/dr-gpu/src/lib.rs#L72), [`core/dr-gpu/src/lib.rs:95`](../../core/dr-gpu/src/lib.rs#L95), [`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:922`](../../core/dr-pipeline/src/graph.rs#L922), [`core/dr-pipeline/src/graph.rs:952`](../../core/dr-pipeline/src/graph.rs#L952), [`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/framing.rs:444`](../../ui/dr-ui/src/develop/framing.rs#L444), [`ui/dr-ui/src/develop/mod.rs:55`](../../ui/dr-ui/src/develop/mod.rs#L55), [`ui/dr-ui/src/develop/render.rs:140`](../../ui/dr-ui/src/develop/render.rs#L140), [`ui/dr-ui/src/develop/render.rs:940`](../../ui/dr-ui/src/develop/render.rs#L940), [`ui/dr-ui/src/develop/render.rs:974`](../../ui/dr-ui/src/develop/render.rs#L974), [`ui/dr-ui/src/lib.rs:1028`](../../ui/dr-ui/src/lib.rs#L1028), [`ui/dr-ui/src/lib.rs:102`](../../ui/dr-ui/src/lib.rs#L102), [`ui/dr-ui/src/lib.rs:1087`](../../ui/dr-ui/src/lib.rs#L1087) |
| 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:527`](../../core/dr-pipeline/src/operation.rs#L527), [`core/dr-types/src/colour.rs:1`](../../core/dr-types/src/colour.rs#L1), [`ui/dr-ui/src/develop/render.rs:1316`](../../ui/dr-ui/src/develop/render.rs#L1316), [`ui/dr-ui/src/develop/render.rs:170`](../../ui/dr-ui/src/develop/render.rs#L170), [`ui/dr-ui/src/lib.rs:2145`](../../ui/dr-ui/src/lib.rs#L2145), [`ui/dr-ui/src/lib.rs:2929`](../../ui/dr-ui/src/lib.rs#L2929) |
-| 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/render.rs:1106`](../../ui/dr-ui/src/develop/render.rs#L1106), [`ui/dr-ui/src/develop/render.rs:1138`](../../ui/dr-ui/src/develop/render.rs#L1138), [`ui/dr-ui/src/develop/render.rs:224`](../../ui/dr-ui/src/develop/render.rs#L224), [`ui/dr-ui/src/develop/session.rs:112`](../../ui/dr-ui/src/develop/session.rs#L112), [`ui/dr-ui/src/histogram.rs:1`](../../ui/dr-ui/src/histogram.rs#L1), [`ui/dr-ui/src/lib.rs:2279`](../../ui/dr-ui/src/lib.rs#L2279), [`ui/dr-ui/src/lib.rs:431`](../../ui/dr-ui/src/lib.rs#L431), [`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/render.rs:116`](../../ui/dr-ui/src/develop/render.rs#L116), [`ui/dr-ui/src/develop/render.rs:1316`](../../ui/dr-ui/src/develop/render.rs#L1316), [`ui/dr-ui/src/develop/render.rs:1362`](../../ui/dr-ui/src/develop/render.rs#L1362), [`ui/dr-ui/src/develop/render.rs:1381`](../../ui/dr-ui/src/develop/render.rs#L1381), [`ui/dr-ui/src/develop/render.rs:170`](../../ui/dr-ui/src/develop/render.rs#L170), [`ui/dr-ui/src/develop/session.rs:265`](../../ui/dr-ui/src/develop/session.rs#L265), [`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:1265`](../../ui/dr-ui/src/lib.rs#L1265), [`ui/dr-ui/src/lib.rs:2145`](../../ui/dr-ui/src/lib.rs#L2145), [`ui/dr-ui/src/lib.rs:2906`](../../ui/dr-ui/src/lib.rs#L2906), [`ui/dr-ui/src/lib.rs:2929`](../../ui/dr-ui/src/lib.rs#L2929), [`ui/dr-ui/ui/app.slint:104`](../../ui/dr-ui/ui/app.slint#L104), [`ui/dr-ui/ui/app.slint:1937`](../../ui/dr-ui/ui/app.slint#L1937), [`ui/dr-ui/ui/settings.slint:165`](../../ui/dr-ui/ui/settings.slint#L165), [`ui/dr-ui/ui/settings.slint:968`](../../ui/dr-ui/ui/settings.slint#L968) |
+| FR-DSP-6 | [`core/dr-pipeline/src/operation.rs:527`](../../core/dr-pipeline/src/operation.rs#L527), [`core/dr-types/src/colour.rs:1`](../../core/dr-types/src/colour.rs#L1), [`ui/dr-ui/src/develop/render.rs:1316`](../../ui/dr-ui/src/develop/render.rs#L1316), [`ui/dr-ui/src/develop/render.rs:170`](../../ui/dr-ui/src/develop/render.rs#L170), [`ui/dr-ui/src/lib.rs:2146`](../../ui/dr-ui/src/lib.rs#L2146), [`ui/dr-ui/src/lib.rs:2930`](../../ui/dr-ui/src/lib.rs#L2930) |
+| 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/render.rs:1106`](../../ui/dr-ui/src/develop/render.rs#L1106), [`ui/dr-ui/src/develop/render.rs:1138`](../../ui/dr-ui/src/develop/render.rs#L1138), [`ui/dr-ui/src/develop/render.rs:224`](../../ui/dr-ui/src/develop/render.rs#L224), [`ui/dr-ui/src/develop/session.rs:112`](../../ui/dr-ui/src/develop/session.rs#L112), [`ui/dr-ui/src/histogram.rs:1`](../../ui/dr-ui/src/histogram.rs#L1), [`ui/dr-ui/src/lib.rs:2280`](../../ui/dr-ui/src/lib.rs#L2280), [`ui/dr-ui/src/lib.rs:432`](../../ui/dr-ui/src/lib.rs#L432), [`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/render.rs:116`](../../ui/dr-ui/src/develop/render.rs#L116), [`ui/dr-ui/src/develop/render.rs:1316`](../../ui/dr-ui/src/develop/render.rs#L1316), [`ui/dr-ui/src/develop/render.rs:1362`](../../ui/dr-ui/src/develop/render.rs#L1362), [`ui/dr-ui/src/develop/render.rs:1381`](../../ui/dr-ui/src/develop/render.rs#L1381), [`ui/dr-ui/src/develop/render.rs:170`](../../ui/dr-ui/src/develop/render.rs#L170), [`ui/dr-ui/src/develop/session.rs:265`](../../ui/dr-ui/src/develop/session.rs#L265), [`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:1266`](../../ui/dr-ui/src/lib.rs#L1266), [`ui/dr-ui/src/lib.rs:2146`](../../ui/dr-ui/src/lib.rs#L2146), [`ui/dr-ui/src/lib.rs:2907`](../../ui/dr-ui/src/lib.rs#L2907), [`ui/dr-ui/src/lib.rs:2930`](../../ui/dr-ui/src/lib.rs#L2930), [`ui/dr-ui/ui/app.slint:105`](../../ui/dr-ui/ui/app.slint#L105), [`ui/dr-ui/ui/app.slint:1673`](../../ui/dr-ui/ui/app.slint#L1673), [`ui/dr-ui/ui/settings.slint:165`](../../ui/dr-ui/ui/settings.slint#L165), [`ui/dr-ui/ui/settings.slint:968`](../../ui/dr-ui/ui/settings.slint#L968) |
| 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:157`](../../core/dr-export/src/lib.rs#L157), [`core/dr-export/src/lib.rs:1`](../../core/dr-export/src/lib.rs#L1), [`core/dr-export/src/lib.rs:57`](../../core/dr-export/src/lib.rs#L57), [`core/dr-gpu/src/adjust.rs:2676`](../../core/dr-gpu/src/adjust.rs#L2676), [`core/dr-pipeline/src/graph.rs:835`](../../core/dr-pipeline/src/graph.rs#L835), [`core/dr-pipeline/src/graph.rs:966`](../../core/dr-pipeline/src/graph.rs#L966), [`core/dr-pipeline/src/operation.rs:527`](../../core/dr-pipeline/src/operation.rs#L527), [`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:963`](../../core/dr-types/src/settings.rs#L963), [`ui/dr-ui/src/develop/render.rs:1381`](../../ui/dr-ui/src/develop/render.rs#L1381), [`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:186`](../../core/dr-export/src/lib.rs#L186), [`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:1008`](../../core/dr-types/src/settings.rs#L1008), [`core/dr-types/src/settings.rs:1016`](../../core/dr-types/src/settings.rs#L1016), [`core/dr-types/src/settings.rs:1032`](../../core/dr-types/src/settings.rs#L1032), [`core/dr-types/src/settings.rs:1101`](../../core/dr-types/src/settings.rs#L1101), [`core/dr-types/src/settings.rs:1129`](../../core/dr-types/src/settings.rs#L1129), [`core/dr-types/src/settings.rs:1140`](../../core/dr-types/src/settings.rs#L1140), [`core/dr-types/src/settings.rs:1146`](../../core/dr-types/src/settings.rs#L1146), [`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), [`ui/dr-ui/src/settings_ui.rs:274`](../../ui/dr-ui/src/settings_ui.rs#L274), [`ui/dr-ui/src/settings_ui.rs:287`](../../ui/dr-ui/src/settings_ui.rs#L287), [`ui/dr-ui/src/settings_ui.rs:302`](../../ui/dr-ui/src/settings_ui.rs#L302), [`ui/dr-ui/src/settings_ui.rs:727`](../../ui/dr-ui/src/settings_ui.rs#L727), [`ui/dr-ui/ui/settings.slint:851`](../../ui/dr-ui/ui/settings.slint#L851), [`ui/dr-ui/ui/settings.slint:861`](../../ui/dr-ui/ui/settings.slint#L861) |
| 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:608`](../../ui/dr-ui/src/lib.rs#L608), [`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:847`](../../ui/dr-ui/src/settings_ui.rs#L847) |
-| FR-EXP-7 | [`ui/dr-ui/src/activity.rs:83`](../../ui/dr-ui/src/activity.rs#L83), [`ui/dr-ui/src/develop_ui.rs:309`](../../ui/dr-ui/src/develop_ui.rs#L309), [`ui/dr-ui/src/export.rs:1005`](../../ui/dr-ui/src/export.rs#L1005), [`ui/dr-ui/src/export.rs:1`](../../ui/dr-ui/src/export.rs#L1), [`ui/dr-ui/src/lib.rs:269`](../../ui/dr-ui/src/lib.rs#L269), [`ui/dr-ui/src/lib.rs:608`](../../ui/dr-ui/src/lib.rs#L608), [`ui/dr-ui/src/lib.rs:654`](../../ui/dr-ui/src/lib.rs#L654), [`ui/dr-ui/src/lib.rs:681`](../../ui/dr-ui/src/lib.rs#L681), [`ui/dr-ui/src/library_ui/controller.rs:1004`](../../ui/dr-ui/src/library_ui/controller.rs#L1004), [`ui/dr-ui/src/library_ui/controller.rs:1016`](../../ui/dr-ui/src/library_ui/controller.rs#L1016), [`ui/dr-ui/src/library_ui/controller.rs:1028`](../../ui/dr-ui/src/library_ui/controller.rs#L1028), [`ui/dr-ui/src/library_ui/controller.rs:716`](../../ui/dr-ui/src/library_ui/controller.rs#L716), [`ui/dr-ui/src/library_ui/controller.rs:816`](../../ui/dr-ui/src/library_ui/controller.rs#L816), [`ui/dr-ui/src/library_ui/controller.rs:873`](../../ui/dr-ui/src/library_ui/controller.rs#L873), [`ui/dr-ui/src/library_ui/sync.rs:97`](../../ui/dr-ui/src/library_ui/sync.rs#L97), [`ui/dr-ui/ui/app.slint:1095`](../../ui/dr-ui/ui/app.slint#L1095), [`ui/dr-ui/ui/app.slint:1672`](../../ui/dr-ui/ui/app.slint#L1672), [`ui/dr-ui/ui/library.slint:1588`](../../ui/dr-ui/ui/library.slint#L1588), [`ui/dr-ui/ui/library.slint:4339`](../../ui/dr-ui/ui/library.slint#L4339) |
-| FR-EXP-8 | [`core/dr-decode/src/lib.rs:366`](../../core/dr-decode/src/lib.rs#L366), [`core/dr-decode/src/lib.rs:390`](../../core/dr-decode/src/lib.rs#L390), [`core/dr-decode/src/lib.rs:404`](../../core/dr-decode/src/lib.rs#L404), [`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:1233`](../../core/dr-decode/src/locate.rs#L1233), [`core/dr-decode/src/locate.rs:1292`](../../core/dr-decode/src/locate.rs#L1292), [`core/dr-decode/src/locate.rs:359`](../../core/dr-decode/src/locate.rs#L359), [`core/dr-decode/src/locate.rs:556`](../../core/dr-decode/src/locate.rs#L556), [`core/dr-decode/src/locate.rs:640`](../../core/dr-decode/src/locate.rs#L640), [`core/dr-decode/src/locate.rs:653`](../../core/dr-decode/src/locate.rs#L653), [`core/dr-decode/src/locate.rs:736`](../../core/dr-decode/src/locate.rs#L736), [`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:140`](../../core/dr-export/src/lib.rs#L140), [`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:671`](../../core/dr-types/src/settings.rs#L671), [`ui/dr-ui/src/develop/session.rs:37`](../../ui/dr-ui/src/develop/session.rs#L37), [`ui/dr-ui/src/develop/session.rs:412`](../../ui/dr-ui/src/develop/session.rs#L412), [`ui/dr-ui/src/develop/session.rs:524`](../../ui/dr-ui/src/develop/session.rs#L524), [`ui/dr-ui/src/export.rs:474`](../../ui/dr-ui/src/export.rs#L474), [`ui/dr-ui/src/export.rs:641`](../../ui/dr-ui/src/export.rs#L641), [`ui/dr-ui/src/export.rs:687`](../../ui/dr-ui/src/export.rs#L687), [`ui/dr-ui/src/export.rs:715`](../../ui/dr-ui/src/export.rs#L715), [`ui/dr-ui/src/export.rs:839`](../../ui/dr-ui/src/export.rs#L839), [`ui/dr-ui/src/export.rs:857`](../../ui/dr-ui/src/export.rs#L857), [`ui/dr-ui/src/lib.rs:269`](../../ui/dr-ui/src/lib.rs#L269), [`ui/dr-ui/src/lib.rs:292`](../../ui/dr-ui/src/lib.rs#L292), [`ui/dr-ui/src/lib.rs:640`](../../ui/dr-ui/src/lib.rs#L640), [`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:546`](../../core/dr-decode/src/lib.rs#L546), [`core/dr-export/src/lib.rs:132`](../../core/dr-export/src/lib.rs#L132), [`core/dr-export/src/lib.rs:1`](../../core/dr-export/src/lib.rs#L1), [`core/dr-gpu/src/adjust.rs:1134`](../../core/dr-gpu/src/adjust.rs#L1134), [`ui/dr-ui/examples/face_native.rs:1`](../../ui/dr-ui/examples/face_native.rs#L1), [`ui/dr-ui/src/develop/mask_ops.rs:1130`](../../ui/dr-ui/src/develop/mask_ops.rs#L1130), [`ui/dr-ui/src/develop/render.rs:546`](../../ui/dr-ui/src/develop/render.rs#L546), [`ui/dr-ui/src/develop/render.rs:584`](../../ui/dr-ui/src/develop/render.rs#L584), [`ui/dr-ui/src/lib.rs:608`](../../ui/dr-ui/src/lib.rs#L608), [`ui/dr-ui/src/library/sweep.rs:506`](../../ui/dr-ui/src/library/sweep.rs#L506), [`ui/dr-ui/tests/export_ignores_the_viewport.rs:1`](../../ui/dr-ui/tests/export_ignores_the_viewport.rs#L1) |
-| FR-MRG-1 | [`core/dr-pano/src/align.rs:1`](../../core/dr-pano/src/align.rs#L1), [`core/dr-pano/src/lib.rs:1`](../../core/dr-pano/src/lib.rs#L1), [`ui/dr-ui/src/lib.rs:1820`](../../ui/dr-ui/src/lib.rs#L1820), [`ui/dr-ui/src/merge.rs:1`](../../ui/dr-ui/src/merge.rs#L1), [`ui/dr-ui/src/merge_ui.rs:1`](../../ui/dr-ui/src/merge_ui.rs#L1), [`ui/dr-ui/ui/app.slint:1677`](../../ui/dr-ui/ui/app.slint#L1677), [`ui/dr-ui/ui/app.slint:786`](../../ui/dr-ui/ui/app.slint#L786), [`ui/dr-ui/ui/library.slint:1596`](../../ui/dr-ui/ui/library.slint#L1596), [`ui/dr-ui/ui/library.slint:4284`](../../ui/dr-ui/ui/library.slint#L4284), [`ui/dr-ui/ui/merge.slint:1`](../../ui/dr-ui/ui/merge.slint#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:609`](../../ui/dr-ui/src/lib.rs#L609), [`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:847`](../../ui/dr-ui/src/settings_ui.rs#L847) |
+| FR-EXP-7 | [`ui/dr-ui/src/activity.rs:83`](../../ui/dr-ui/src/activity.rs#L83), [`ui/dr-ui/src/develop_ui.rs:309`](../../ui/dr-ui/src/develop_ui.rs#L309), [`ui/dr-ui/src/export.rs:1006`](../../ui/dr-ui/src/export.rs#L1006), [`ui/dr-ui/src/export.rs:1`](../../ui/dr-ui/src/export.rs#L1), [`ui/dr-ui/src/lib.rs:270`](../../ui/dr-ui/src/lib.rs#L270), [`ui/dr-ui/src/lib.rs:609`](../../ui/dr-ui/src/lib.rs#L609), [`ui/dr-ui/src/lib.rs:655`](../../ui/dr-ui/src/lib.rs#L655), [`ui/dr-ui/src/lib.rs:682`](../../ui/dr-ui/src/lib.rs#L682), [`ui/dr-ui/src/library_ui/controller.rs:1004`](../../ui/dr-ui/src/library_ui/controller.rs#L1004), [`ui/dr-ui/src/library_ui/controller.rs:1016`](../../ui/dr-ui/src/library_ui/controller.rs#L1016), [`ui/dr-ui/src/library_ui/controller.rs:1028`](../../ui/dr-ui/src/library_ui/controller.rs#L1028), [`ui/dr-ui/src/library_ui/controller.rs:716`](../../ui/dr-ui/src/library_ui/controller.rs#L716), [`ui/dr-ui/src/library_ui/controller.rs:816`](../../ui/dr-ui/src/library_ui/controller.rs#L816), [`ui/dr-ui/src/library_ui/controller.rs:873`](../../ui/dr-ui/src/library_ui/controller.rs#L873), [`ui/dr-ui/src/library_ui/sync.rs:97`](../../ui/dr-ui/src/library_ui/sync.rs#L97), [`ui/dr-ui/ui/app.slint:1408`](../../ui/dr-ui/ui/app.slint#L1408), [`ui/dr-ui/ui/app.slint:838`](../../ui/dr-ui/ui/app.slint#L838), [`ui/dr-ui/ui/library.slint:1858`](../../ui/dr-ui/ui/library.slint#L1858), [`ui/dr-ui/ui/library.slint:4609`](../../ui/dr-ui/ui/library.slint#L4609) |
+| FR-EXP-8 | [`core/dr-decode/src/lib.rs:366`](../../core/dr-decode/src/lib.rs#L366), [`core/dr-decode/src/lib.rs:390`](../../core/dr-decode/src/lib.rs#L390), [`core/dr-decode/src/lib.rs:404`](../../core/dr-decode/src/lib.rs#L404), [`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:1233`](../../core/dr-decode/src/locate.rs#L1233), [`core/dr-decode/src/locate.rs:1292`](../../core/dr-decode/src/locate.rs#L1292), [`core/dr-decode/src/locate.rs:359`](../../core/dr-decode/src/locate.rs#L359), [`core/dr-decode/src/locate.rs:556`](../../core/dr-decode/src/locate.rs#L556), [`core/dr-decode/src/locate.rs:640`](../../core/dr-decode/src/locate.rs#L640), [`core/dr-decode/src/locate.rs:653`](../../core/dr-decode/src/locate.rs#L653), [`core/dr-decode/src/locate.rs:736`](../../core/dr-decode/src/locate.rs#L736), [`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:140`](../../core/dr-export/src/lib.rs#L140), [`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:671`](../../core/dr-types/src/settings.rs#L671), [`ui/dr-ui/src/develop/session.rs:37`](../../ui/dr-ui/src/develop/session.rs#L37), [`ui/dr-ui/src/develop/session.rs:412`](../../ui/dr-ui/src/develop/session.rs#L412), [`ui/dr-ui/src/develop/session.rs:524`](../../ui/dr-ui/src/develop/session.rs#L524), [`ui/dr-ui/src/export.rs:475`](../../ui/dr-ui/src/export.rs#L475), [`ui/dr-ui/src/export.rs:642`](../../ui/dr-ui/src/export.rs#L642), [`ui/dr-ui/src/export.rs:688`](../../ui/dr-ui/src/export.rs#L688), [`ui/dr-ui/src/export.rs:716`](../../ui/dr-ui/src/export.rs#L716), [`ui/dr-ui/src/export.rs:840`](../../ui/dr-ui/src/export.rs#L840), [`ui/dr-ui/src/export.rs:858`](../../ui/dr-ui/src/export.rs#L858), [`ui/dr-ui/src/lib.rs:270`](../../ui/dr-ui/src/lib.rs#L270), [`ui/dr-ui/src/lib.rs:293`](../../ui/dr-ui/src/lib.rs#L293), [`ui/dr-ui/src/lib.rs:641`](../../ui/dr-ui/src/lib.rs#L641), [`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:546`](../../core/dr-decode/src/lib.rs#L546), [`core/dr-export/src/lib.rs:132`](../../core/dr-export/src/lib.rs#L132), [`core/dr-export/src/lib.rs:1`](../../core/dr-export/src/lib.rs#L1), [`core/dr-gpu/src/adjust.rs:1134`](../../core/dr-gpu/src/adjust.rs#L1134), [`ui/dr-ui/examples/face_native.rs:1`](../../ui/dr-ui/examples/face_native.rs#L1), [`ui/dr-ui/src/develop/mask_ops.rs:1130`](../../ui/dr-ui/src/develop/mask_ops.rs#L1130), [`ui/dr-ui/src/develop/render.rs:546`](../../ui/dr-ui/src/develop/render.rs#L546), [`ui/dr-ui/src/develop/render.rs:584`](../../ui/dr-ui/src/develop/render.rs#L584), [`ui/dr-ui/src/lib.rs:609`](../../ui/dr-ui/src/lib.rs#L609), [`ui/dr-ui/src/library/sweep.rs:506`](../../ui/dr-ui/src/library/sweep.rs#L506), [`ui/dr-ui/tests/export_ignores_the_viewport.rs:1`](../../ui/dr-ui/tests/export_ignores_the_viewport.rs#L1) |
+| FR-MRG-1 | [`core/dr-pano/src/align.rs:1`](../../core/dr-pano/src/align.rs#L1), [`core/dr-pano/src/lib.rs:1`](../../core/dr-pano/src/lib.rs#L1), [`ui/dr-ui/src/lib.rs:1821`](../../ui/dr-ui/src/lib.rs#L1821), [`ui/dr-ui/src/merge.rs:1`](../../ui/dr-ui/src/merge.rs#L1), [`ui/dr-ui/src/merge_ui.rs:1`](../../ui/dr-ui/src/merge_ui.rs#L1), [`ui/dr-ui/ui/app.slint:1413`](../../ui/dr-ui/ui/app.slint#L1413), [`ui/dr-ui/ui/app.slint:531`](../../ui/dr-ui/ui/app.slint#L531), [`ui/dr-ui/ui/library.slint:1866`](../../ui/dr-ui/ui/library.slint#L1866), [`ui/dr-ui/ui/library.slint:4554`](../../ui/dr-ui/ui/library.slint#L4554), [`ui/dr-ui/ui/merge.slint:1`](../../ui/dr-ui/ui/merge.slint#L1) |
| FR-MRG-10 | [`core/dr-gpu/src/merge.rs:1`](../../core/dr-gpu/src/merge.rs#L1), [`core/dr-gpu/src/shaders/merge.wgsl:1`](../../core/dr-gpu/src/shaders/merge.wgsl#L1), [`core/dr-pano/src/lib.rs:1`](../../core/dr-pano/src/lib.rs#L1) |
| FR-MRG-11 | [`core/dr-gpu/src/merge.rs:1`](../../core/dr-gpu/src/merge.rs#L1), [`core/dr-gpu/src/shaders/merge.wgsl:1`](../../core/dr-gpu/src/shaders/merge.wgsl#L1) |
| FR-MRG-2 | [`core/dr-gpu/src/adjust.rs:104`](../../core/dr-gpu/src/adjust.rs#L104), [`core/dr-gpu/src/adjust.rs:1157`](../../core/dr-gpu/src/adjust.rs#L1157), [`core/dr-gpu/src/adjust.rs:1276`](../../core/dr-gpu/src/adjust.rs#L1276), [`core/dr-gpu/src/adjust.rs:316`](../../core/dr-gpu/src/adjust.rs#L316), [`core/dr-pipeline/src/graph.rs:852`](../../core/dr-pipeline/src/graph.rs#L852), [`core/dr-pipeline/src/operation.rs:2183`](../../core/dr-pipeline/src/operation.rs#L2183), [`core/dr-pipeline/src/operation.rs:427`](../../core/dr-pipeline/src/operation.rs#L427), [`core/dr-pipeline/src/operation.rs:612`](../../core/dr-pipeline/src/operation.rs#L612), [`core/dr-pipeline/src/operation.rs:916`](../../core/dr-pipeline/src/operation.rs#L916), [`ui/dr-ui/src/merge.rs:1`](../../ui/dr-ui/src/merge.rs#L1) |
@@ -108,75 +108,75 @@ A tag naming an ID `requirements.md` does not define — what renumbering produc
| FR-MRG-4 | [`core/dr-export/src/inscribed.rs:1`](../../core/dr-export/src/inscribed.rs#L1), [`core/dr-pano/src/fill.rs:1`](../../core/dr-pano/src/fill.rs#L1), [`core/dr-pano/src/migan.rs:1`](../../core/dr-pano/src/migan.rs#L1), [`core/dr-pano/src/projection.rs:1`](../../core/dr-pano/src/projection.rs#L1), [`ui/dr-ui/src/library/paths.rs:365`](../../ui/dr-ui/src/library/paths.rs#L365), [`ui/dr-ui/src/library/paths.rs:369`](../../ui/dr-ui/src/library/paths.rs#L369), [`ui/dr-ui/src/merge.rs:143`](../../ui/dr-ui/src/merge.rs#L143), [`ui/dr-ui/src/merge_ui.rs:1`](../../ui/dr-ui/src/merge_ui.rs#L1), [`ui/dr-ui/ui/merge.slint:1`](../../ui/dr-ui/ui/merge.slint#L1), [`ui/dr-ui/ui/merge.slint:46`](../../ui/dr-ui/ui/merge.slint#L46) |
| FR-MRG-5 | [`core/dr-pano/src/align.rs:1`](../../core/dr-pano/src/align.rs#L1), [`ui/dr-ui/src/merge.rs:1`](../../ui/dr-ui/src/merge.rs#L1), [`ui/dr-ui/src/merge_ui.rs:1`](../../ui/dr-ui/src/merge_ui.rs#L1), [`ui/dr-ui/ui/merge.slint:1`](../../ui/dr-ui/ui/merge.slint#L1) |
| FR-MRG-6 | [`core/dr-pipeline/src/sidecar.rs:1033`](../../core/dr-pipeline/src/sidecar.rs#L1033), [`core/dr-pipeline/src/sidecar.rs:113`](../../core/dr-pipeline/src/sidecar.rs#L113), [`core/dr-pipeline/src/sidecar.rs:123`](../../core/dr-pipeline/src/sidecar.rs#L123), [`core/dr-pipeline/src/sidecar.rs:2241`](../../core/dr-pipeline/src/sidecar.rs#L2241), [`core/dr-pipeline/src/sidecar.rs:841`](../../core/dr-pipeline/src/sidecar.rs#L841), [`ui/dr-ui/src/merge.rs:842`](../../ui/dr-ui/src/merge.rs#L842) |
-| FR-MRG-7 | [`ui/dr-ui/src/merge.rs:1`](../../ui/dr-ui/src/merge.rs#L1), [`ui/dr-ui/src/merge_ui.rs:1`](../../ui/dr-ui/src/merge_ui.rs#L1), [`ui/dr-ui/ui/app.slint:786`](../../ui/dr-ui/ui/app.slint#L786), [`ui/dr-ui/ui/merge.slint:1`](../../ui/dr-ui/ui/merge.slint#L1) |
+| FR-MRG-7 | [`ui/dr-ui/src/merge.rs:1`](../../ui/dr-ui/src/merge.rs#L1), [`ui/dr-ui/src/merge_ui.rs:1`](../../ui/dr-ui/src/merge_ui.rs#L1), [`ui/dr-ui/ui/app.slint:531`](../../ui/dr-ui/ui/app.slint#L531), [`ui/dr-ui/ui/merge.slint:1`](../../ui/dr-ui/ui/merge.slint#L1) |
| FR-MRG-8 | [`core/dr-pano/src/xfeat.rs:1`](../../core/dr-pano/src/xfeat.rs#L1), [`core/dr-segment/examples/onnx_probe.rs:1`](../../core/dr-segment/examples/onnx_probe.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:375`](../../core/dr-sync/src/account.rs#L375), [`ui/dr-ui/src/launch.rs:316`](../../ui/dr-ui/src/launch.rs#L316), [`ui/dr-ui/src/launch.rs:61`](../../ui/dr-ui/src/launch.rs#L61), [`ui/dr-ui/src/launch_ui.rs:446`](../../ui/dr-ui/src/launch_ui.rs#L446) |
-| FR-NC-10 | [`core/dr-sync/src/account.rs:240`](../../core/dr-sync/src/account.rs#L240), [`ui/dr-ui/src/export.rs:1`](../../ui/dr-ui/src/export.rs#L1), [`ui/dr-ui/src/lib.rs:681`](../../ui/dr-ui/src/lib.rs#L681), [`ui/dr-ui/src/library/paths.rs:69`](../../ui/dr-ui/src/library/paths.rs#L69), [`ui/dr-ui/src/library/sidecar.rs:100`](../../ui/dr-ui/src/library/sidecar.rs#L100), [`ui/dr-ui/src/library/sidecar.rs:427`](../../ui/dr-ui/src/library/sidecar.rs#L427), [`ui/dr-ui/src/library/thumbnails_fetch.rs:449`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L449), [`ui/dr-ui/src/library_ui/controller.rs:657`](../../ui/dr-ui/src/library_ui/controller.rs#L657), [`ui/dr-ui/src/library_ui/offline.rs:598`](../../ui/dr-ui/src/library_ui/offline.rs#L598), [`ui/dr-ui/src/library_ui/sync.rs:97`](../../ui/dr-ui/src/library_ui/sync.rs#L97), [`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:240`](../../core/dr-sync/src/account.rs#L240), [`ui/dr-ui/src/export.rs:1`](../../ui/dr-ui/src/export.rs#L1), [`ui/dr-ui/src/lib.rs:682`](../../ui/dr-ui/src/lib.rs#L682), [`ui/dr-ui/src/library/paths.rs:69`](../../ui/dr-ui/src/library/paths.rs#L69), [`ui/dr-ui/src/library/sidecar.rs:100`](../../ui/dr-ui/src/library/sidecar.rs#L100), [`ui/dr-ui/src/library/sidecar.rs:427`](../../ui/dr-ui/src/library/sidecar.rs#L427), [`ui/dr-ui/src/library/thumbnails_fetch.rs:449`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L449), [`ui/dr-ui/src/library_ui/controller.rs:657`](../../ui/dr-ui/src/library_ui/controller.rs#L657), [`ui/dr-ui/src/library_ui/offline.rs:623`](../../ui/dr-ui/src/library_ui/offline.rs#L623), [`ui/dr-ui/src/library_ui/sync.rs:97`](../../ui/dr-ui/src/library_ui/sync.rs#L97), [`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:1049`](../../core/dr-sync-nextcloud/src/lib.rs#L1049), [`core/dr-sync-nextcloud/src/lib.rs:40`](../../core/dr-sync-nextcloud/src/lib.rs#L40), [`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:87`](../../core/dr-sync/src/account.rs#L87), [`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:345`](../../ui/dr-ui/src/launch_ui.rs#L345), [`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:318`](../../core/dr-sync/src/account.rs#L318), [`core/dr-sync/src/account.rs:375`](../../core/dr-sync/src/account.rs#L375), [`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/mod.rs:1`](../../ui/dr-ui/src/library/mod.rs#L1), [`ui/dr-ui/src/library/sweep.rs:557`](../../ui/dr-ui/src/library/sweep.rs#L557), [`ui/dr-ui/src/library_ui/grid.rs:443`](../../ui/dr-ui/src/library_ui/grid.rs#L443), [`ui/dr-ui/src/library_ui/mod.rs:1`](../../ui/dr-ui/src/library_ui/mod.rs#L1), [`ui/dr-ui/src/library_ui/sync.rs:363`](../../ui/dr-ui/src/library_ui/sync.rs#L363), [`ui/dr-ui/ui/app.slint:430`](../../ui/dr-ui/ui/app.slint#L430), [`ui/dr-ui/ui/settings.slint:435`](../../ui/dr-ui/ui/settings.slint#L435), [`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/mod.rs:1`](../../ui/dr-ui/src/library/mod.rs#L1), [`ui/dr-ui/src/library/sweep.rs:557`](../../ui/dr-ui/src/library/sweep.rs#L557), [`ui/dr-ui/src/library_ui/grid.rs:458`](../../ui/dr-ui/src/library_ui/grid.rs#L458), [`ui/dr-ui/src/library_ui/mod.rs:1`](../../ui/dr-ui/src/library_ui/mod.rs#L1), [`ui/dr-ui/src/library_ui/sync.rs:368`](../../ui/dr-ui/src/library_ui/sync.rs#L368), [`ui/dr-ui/ui/library.slint:730`](../../ui/dr-ui/ui/library.slint#L730), [`ui/dr-ui/ui/settings.slint:435`](../../ui/dr-ui/ui/settings.slint#L435), [`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:129`](../../core/dr-sync/src/scan.rs#L129), [`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:1182`](../../core/dr-catalog/src/schema.rs#L1182), [`core/dr-catalog/src/schema.rs:1637`](../../core/dr-catalog/src/schema.rs#L1637), [`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/rename_menu.rs:75`](../../ui/dr-ui/src/collections_ui/rename_menu.rs#L75), [`ui/dr-ui/src/collections_ui/tree_sync.rs:111`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L111), [`ui/dr-ui/src/collections_ui/tree_sync.rs:385`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L385), [`ui/dr-ui/src/collections_ui/tree_sync.rs:38`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L38), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:555`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L555), [`ui/dr-ui/src/lib.rs:1572`](../../ui/dr-ui/src/lib.rs#L1572), [`ui/dr-ui/src/lib.rs:2721`](../../ui/dr-ui/src/lib.rs#L2721), [`ui/dr-ui/src/lib.rs:2792`](../../ui/dr-ui/src/lib.rs#L2792), [`ui/dr-ui/src/lib.rs:3010`](../../ui/dr-ui/src/lib.rs#L3010), [`ui/dr-ui/src/lib.rs:3011`](../../ui/dr-ui/src/lib.rs#L3011), [`ui/dr-ui/src/lib.rs:3050`](../../ui/dr-ui/src/lib.rs#L3050), [`ui/dr-ui/src/library/thumbnails_fetch.rs:118`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L118), [`ui/dr-ui/src/library/thumbnails_fetch.rs:393`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L393), [`ui/dr-ui/src/library/thumbnails_fetch.rs:574`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L574), [`ui/dr-ui/src/library/thumbnails_fetch.rs:711`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L711), [`ui/dr-ui/src/library/thumbnails_fetch.rs:726`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L726), [`ui/dr-ui/src/library/thumbnails_fetch.rs:95`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L95), [`ui/dr-ui/src/library_ui/controller.rs:339`](../../ui/dr-ui/src/library_ui/controller.rs#L339), [`ui/dr-ui/src/library_ui/controller.rs:350`](../../ui/dr-ui/src/library_ui/controller.rs#L350), [`ui/dr-ui/src/library_ui/controller.rs:365`](../../ui/dr-ui/src/library_ui/controller.rs#L365), [`ui/dr-ui/src/library_ui/controller.rs:374`](../../ui/dr-ui/src/library_ui/controller.rs#L374), [`ui/dr-ui/src/library_ui/controller.rs:382`](../../ui/dr-ui/src/library_ui/controller.rs#L382), [`ui/dr-ui/src/library_ui/controller.rs:512`](../../ui/dr-ui/src/library_ui/controller.rs#L512), [`ui/dr-ui/src/library_ui/controller.rs:522`](../../ui/dr-ui/src/library_ui/controller.rs#L522), [`ui/dr-ui/src/library_ui/controller.rs:537`](../../ui/dr-ui/src/library_ui/controller.rs#L537), [`ui/dr-ui/src/library_ui/controller.rs:584`](../../ui/dr-ui/src/library_ui/controller.rs#L584), [`ui/dr-ui/src/library_ui/controller.rs:599`](../../ui/dr-ui/src/library_ui/controller.rs#L599), [`ui/dr-ui/src/library_ui/controller.rs:673`](../../ui/dr-ui/src/library_ui/controller.rs#L673), [`ui/dr-ui/src/library_ui/controller.rs:704`](../../ui/dr-ui/src/library_ui/controller.rs#L704), [`ui/dr-ui/src/library_ui/controller.rs:716`](../../ui/dr-ui/src/library_ui/controller.rs#L716), [`ui/dr-ui/src/library_ui/filter_bar.rs:397`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L397), [`ui/dr-ui/src/library_ui/filter_bar.rs:415`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L415), [`ui/dr-ui/src/library_ui/offline.rs:194`](../../ui/dr-ui/src/library_ui/offline.rs#L194), [`ui/dr-ui/src/library_ui/offline.rs:20`](../../ui/dr-ui/src/library_ui/offline.rs#L20), [`ui/dr-ui/src/library_ui/offline.rs:249`](../../ui/dr-ui/src/library_ui/offline.rs#L249), [`ui/dr-ui/src/library_ui/offline.rs:387`](../../ui/dr-ui/src/library_ui/offline.rs#L387), [`ui/dr-ui/src/library_ui/offline.rs:505`](../../ui/dr-ui/src/library_ui/offline.rs#L505), [`ui/dr-ui/src/library_ui/offline.rs:93`](../../ui/dr-ui/src/library_ui/offline.rs#L93), [`ui/dr-ui/src/library_ui/window.rs:228`](../../ui/dr-ui/src/library_ui/window.rs#L228), [`ui/dr-ui/src/settings_store.rs:1`](../../ui/dr-ui/src/settings_store.rs#L1), [`ui/dr-ui/src/settings_ui.rs:157`](../../ui/dr-ui/src/settings_ui.rs#L157), [`ui/dr-ui/src/settings_ui.rs:1`](../../ui/dr-ui/src/settings_ui.rs#L1), [`ui/dr-ui/src/settings_ui.rs:542`](../../ui/dr-ui/src/settings_ui.rs#L542), [`ui/dr-ui/ui/app.slint:1566`](../../ui/dr-ui/ui/app.slint#L1566), [`ui/dr-ui/ui/app.slint:3119`](../../ui/dr-ui/ui/app.slint#L3119), [`ui/dr-ui/ui/app.slint:558`](../../ui/dr-ui/ui/app.slint#L558), [`ui/dr-ui/ui/collections.slint:1037`](../../ui/dr-ui/ui/collections.slint#L1037), [`ui/dr-ui/ui/collections.slint:1048`](../../ui/dr-ui/ui/collections.slint#L1048), [`ui/dr-ui/ui/collections.slint:1127`](../../ui/dr-ui/ui/collections.slint#L1127), [`ui/dr-ui/ui/collections.slint:1228`](../../ui/dr-ui/ui/collections.slint#L1228), [`ui/dr-ui/ui/collections.slint:1236`](../../ui/dr-ui/ui/collections.slint#L1236), [`ui/dr-ui/ui/collections.slint:272`](../../ui/dr-ui/ui/collections.slint#L272), [`ui/dr-ui/ui/collections.slint:424`](../../ui/dr-ui/ui/collections.slint#L424), [`ui/dr-ui/ui/collections.slint:433`](../../ui/dr-ui/ui/collections.slint#L433), [`ui/dr-ui/ui/collections.slint:436`](../../ui/dr-ui/ui/collections.slint#L436), [`ui/dr-ui/ui/collections.slint:482`](../../ui/dr-ui/ui/collections.slint#L482), [`ui/dr-ui/ui/collections.slint:52`](../../ui/dr-ui/ui/collections.slint#L52), [`ui/dr-ui/ui/collections.slint:720`](../../ui/dr-ui/ui/collections.slint#L720), [`ui/dr-ui/ui/collections.slint:877`](../../ui/dr-ui/ui/collections.slint#L877), [`ui/dr-ui/ui/collections.slint:91`](../../ui/dr-ui/ui/collections.slint#L91), [`ui/dr-ui/ui/icons.slint:262`](../../ui/dr-ui/ui/icons.slint#L262), [`ui/dr-ui/ui/settings.slint:114`](../../ui/dr-ui/ui/settings.slint#L114), [`ui/dr-ui/ui/settings.slint:656`](../../ui/dr-ui/ui/settings.slint#L656) |
-| FR-NC-6b | [`ui/dr-ui/src/library_ui/offline.rs:249`](../../ui/dr-ui/src/library_ui/offline.rs#L249), [`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:172`](../../core/dr-sync-nextcloud/src/desktop_client.rs#L172), [`core/dr-sync-nextcloud/src/desktop_client.rs:35`](../../core/dr-sync-nextcloud/src/desktop_client.rs#L35), [`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/tree_sync.rs:111`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L111), [`ui/dr-ui/src/collections_ui/tree_sync.rs:385`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L385), [`ui/dr-ui/src/collections_ui/tree_sync.rs:38`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L38), [`ui/dr-ui/src/derived_sync.rs:1042`](../../ui/dr-ui/src/derived_sync.rs#L1042), [`ui/dr-ui/src/derived_sync.rs:642`](../../ui/dr-ui/src/derived_sync.rs#L642), [`ui/dr-ui/src/library/sidecar.rs:531`](../../ui/dr-ui/src/library/sidecar.rs#L531), [`ui/dr-ui/src/library/sweep.rs:677`](../../ui/dr-ui/src/library/sweep.rs#L677), [`ui/dr-ui/src/library/thumbnails_fetch.rs:215`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L215), [`ui/dr-ui/src/library/thumbnails_fetch.rs:305`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L305), [`ui/dr-ui/src/library_ui/offline.rs:20`](../../ui/dr-ui/src/library_ui/offline.rs#L20), [`ui/dr-ui/src/library_ui/offline.rs:292`](../../ui/dr-ui/src/library_ui/offline.rs#L292), [`ui/dr-ui/src/library_ui/offline.rs:93`](../../ui/dr-ui/src/library_ui/offline.rs#L93), [`ui/dr-ui/src/remote.rs:40`](../../ui/dr-ui/src/remote.rs#L40), [`ui/dr-ui/src/repairs.rs:1140`](../../ui/dr-ui/src/repairs.rs#L1140), [`ui/dr-ui/ui/collections.slint:272`](../../ui/dr-ui/ui/collections.slint#L272), [`ui/dr-ui/ui/collections.slint:877`](../../ui/dr-ui/ui/collections.slint#L877), [`ui/dr-ui/ui/icons.slint:262`](../../ui/dr-ui/ui/icons.slint#L262) |
+| 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:1182`](../../core/dr-catalog/src/schema.rs#L1182), [`core/dr-catalog/src/schema.rs:1637`](../../core/dr-catalog/src/schema.rs#L1637), [`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/rename_menu.rs:75`](../../ui/dr-ui/src/collections_ui/rename_menu.rs#L75), [`ui/dr-ui/src/collections_ui/tree_sync.rs:111`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L111), [`ui/dr-ui/src/collections_ui/tree_sync.rs:387`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L387), [`ui/dr-ui/src/collections_ui/tree_sync.rs:38`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L38), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:560`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L560), [`ui/dr-ui/src/lib.rs:1573`](../../ui/dr-ui/src/lib.rs#L1573), [`ui/dr-ui/src/lib.rs:2722`](../../ui/dr-ui/src/lib.rs#L2722), [`ui/dr-ui/src/lib.rs:2793`](../../ui/dr-ui/src/lib.rs#L2793), [`ui/dr-ui/src/lib.rs:3011`](../../ui/dr-ui/src/lib.rs#L3011), [`ui/dr-ui/src/lib.rs:3012`](../../ui/dr-ui/src/lib.rs#L3012), [`ui/dr-ui/src/lib.rs:3051`](../../ui/dr-ui/src/lib.rs#L3051), [`ui/dr-ui/src/library/thumbnails_fetch.rs:118`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L118), [`ui/dr-ui/src/library/thumbnails_fetch.rs:393`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L393), [`ui/dr-ui/src/library/thumbnails_fetch.rs:574`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L574), [`ui/dr-ui/src/library/thumbnails_fetch.rs:711`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L711), [`ui/dr-ui/src/library/thumbnails_fetch.rs:726`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L726), [`ui/dr-ui/src/library/thumbnails_fetch.rs:95`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L95), [`ui/dr-ui/src/library_ui/controller.rs:339`](../../ui/dr-ui/src/library_ui/controller.rs#L339), [`ui/dr-ui/src/library_ui/controller.rs:350`](../../ui/dr-ui/src/library_ui/controller.rs#L350), [`ui/dr-ui/src/library_ui/controller.rs:365`](../../ui/dr-ui/src/library_ui/controller.rs#L365), [`ui/dr-ui/src/library_ui/controller.rs:374`](../../ui/dr-ui/src/library_ui/controller.rs#L374), [`ui/dr-ui/src/library_ui/controller.rs:382`](../../ui/dr-ui/src/library_ui/controller.rs#L382), [`ui/dr-ui/src/library_ui/controller.rs:512`](../../ui/dr-ui/src/library_ui/controller.rs#L512), [`ui/dr-ui/src/library_ui/controller.rs:522`](../../ui/dr-ui/src/library_ui/controller.rs#L522), [`ui/dr-ui/src/library_ui/controller.rs:537`](../../ui/dr-ui/src/library_ui/controller.rs#L537), [`ui/dr-ui/src/library_ui/controller.rs:584`](../../ui/dr-ui/src/library_ui/controller.rs#L584), [`ui/dr-ui/src/library_ui/controller.rs:599`](../../ui/dr-ui/src/library_ui/controller.rs#L599), [`ui/dr-ui/src/library_ui/controller.rs:673`](../../ui/dr-ui/src/library_ui/controller.rs#L673), [`ui/dr-ui/src/library_ui/controller.rs:704`](../../ui/dr-ui/src/library_ui/controller.rs#L704), [`ui/dr-ui/src/library_ui/controller.rs:716`](../../ui/dr-ui/src/library_ui/controller.rs#L716), [`ui/dr-ui/src/library_ui/filter_bar.rs:424`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L424), [`ui/dr-ui/src/library_ui/filter_bar.rs:444`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L444), [`ui/dr-ui/src/library_ui/offline.rs:196`](../../ui/dr-ui/src/library_ui/offline.rs#L196), [`ui/dr-ui/src/library_ui/offline.rs:20`](../../ui/dr-ui/src/library_ui/offline.rs#L20), [`ui/dr-ui/src/library_ui/offline.rs:261`](../../ui/dr-ui/src/library_ui/offline.rs#L261), [`ui/dr-ui/src/library_ui/offline.rs:407`](../../ui/dr-ui/src/library_ui/offline.rs#L407), [`ui/dr-ui/src/library_ui/offline.rs:528`](../../ui/dr-ui/src/library_ui/offline.rs#L528), [`ui/dr-ui/src/library_ui/offline.rs:93`](../../ui/dr-ui/src/library_ui/offline.rs#L93), [`ui/dr-ui/src/library_ui/window.rs:228`](../../ui/dr-ui/src/library_ui/window.rs#L228), [`ui/dr-ui/src/settings_store.rs:1`](../../ui/dr-ui/src/settings_store.rs#L1), [`ui/dr-ui/src/settings_ui.rs:157`](../../ui/dr-ui/src/settings_ui.rs#L157), [`ui/dr-ui/src/settings_ui.rs:1`](../../ui/dr-ui/src/settings_ui.rs#L1), [`ui/dr-ui/src/settings_ui.rs:542`](../../ui/dr-ui/src/settings_ui.rs#L542), [`ui/dr-ui/ui/app.slint:1302`](../../ui/dr-ui/ui/app.slint#L1302), [`ui/dr-ui/ui/app.slint:2854`](../../ui/dr-ui/ui/app.slint#L2854), [`ui/dr-ui/ui/app.slint:426`](../../ui/dr-ui/ui/app.slint#L426), [`ui/dr-ui/ui/collections.slint:1037`](../../ui/dr-ui/ui/collections.slint#L1037), [`ui/dr-ui/ui/collections.slint:1048`](../../ui/dr-ui/ui/collections.slint#L1048), [`ui/dr-ui/ui/collections.slint:1127`](../../ui/dr-ui/ui/collections.slint#L1127), [`ui/dr-ui/ui/collections.slint:1228`](../../ui/dr-ui/ui/collections.slint#L1228), [`ui/dr-ui/ui/collections.slint:1236`](../../ui/dr-ui/ui/collections.slint#L1236), [`ui/dr-ui/ui/collections.slint:272`](../../ui/dr-ui/ui/collections.slint#L272), [`ui/dr-ui/ui/collections.slint:424`](../../ui/dr-ui/ui/collections.slint#L424), [`ui/dr-ui/ui/collections.slint:433`](../../ui/dr-ui/ui/collections.slint#L433), [`ui/dr-ui/ui/collections.slint:436`](../../ui/dr-ui/ui/collections.slint#L436), [`ui/dr-ui/ui/collections.slint:482`](../../ui/dr-ui/ui/collections.slint#L482), [`ui/dr-ui/ui/collections.slint:52`](../../ui/dr-ui/ui/collections.slint#L52), [`ui/dr-ui/ui/collections.slint:720`](../../ui/dr-ui/ui/collections.slint#L720), [`ui/dr-ui/ui/collections.slint:877`](../../ui/dr-ui/ui/collections.slint#L877), [`ui/dr-ui/ui/collections.slint:91`](../../ui/dr-ui/ui/collections.slint#L91), [`ui/dr-ui/ui/icons.slint:262`](../../ui/dr-ui/ui/icons.slint#L262), [`ui/dr-ui/ui/settings.slint:114`](../../ui/dr-ui/ui/settings.slint#L114), [`ui/dr-ui/ui/settings.slint:656`](../../ui/dr-ui/ui/settings.slint#L656) |
+| FR-NC-6b | [`ui/dr-ui/src/library_ui/offline.rs:261`](../../ui/dr-ui/src/library_ui/offline.rs#L261), [`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:172`](../../core/dr-sync-nextcloud/src/desktop_client.rs#L172), [`core/dr-sync-nextcloud/src/desktop_client.rs:35`](../../core/dr-sync-nextcloud/src/desktop_client.rs#L35), [`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/tree_sync.rs:111`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L111), [`ui/dr-ui/src/collections_ui/tree_sync.rs:387`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L387), [`ui/dr-ui/src/collections_ui/tree_sync.rs:38`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L38), [`ui/dr-ui/src/derived_sync.rs:1042`](../../ui/dr-ui/src/derived_sync.rs#L1042), [`ui/dr-ui/src/derived_sync.rs:642`](../../ui/dr-ui/src/derived_sync.rs#L642), [`ui/dr-ui/src/library/sidecar.rs:531`](../../ui/dr-ui/src/library/sidecar.rs#L531), [`ui/dr-ui/src/library/sweep.rs:677`](../../ui/dr-ui/src/library/sweep.rs#L677), [`ui/dr-ui/src/library/thumbnails_fetch.rs:215`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L215), [`ui/dr-ui/src/library/thumbnails_fetch.rs:305`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L305), [`ui/dr-ui/src/library_ui/offline.rs:20`](../../ui/dr-ui/src/library_ui/offline.rs#L20), [`ui/dr-ui/src/library_ui/offline.rs:310`](../../ui/dr-ui/src/library_ui/offline.rs#L310), [`ui/dr-ui/src/library_ui/offline.rs:93`](../../ui/dr-ui/src/library_ui/offline.rs#L93), [`ui/dr-ui/src/remote.rs:40`](../../ui/dr-ui/src/remote.rs#L40), [`ui/dr-ui/src/repairs.rs:1140`](../../ui/dr-ui/src/repairs.rs#L1140), [`ui/dr-ui/ui/collections.slint:272`](../../ui/dr-ui/ui/collections.slint#L272), [`ui/dr-ui/ui/collections.slint:877`](../../ui/dr-ui/ui/collections.slint#L877), [`ui/dr-ui/ui/icons.slint:262`](../../ui/dr-ui/ui/icons.slint#L262) |
| 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:120`](../../core/dr-sync-nextcloud/src/lib.rs#L120), [`ui/dr-ui/src/derived_sync.rs:1`](../../ui/dr-ui/src/derived_sync.rs#L1), [`ui/dr-ui/src/library/sweep.rs:557`](../../ui/dr-ui/src/library/sweep.rs#L557), [`ui/dr-ui/src/library_ui/sync.rs:363`](../../ui/dr-ui/src/library_ui/sync.rs#L363), [`ui/dr-ui/ui/settings.slint:435`](../../ui/dr-ui/ui/settings.slint#L435) |
-| 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:377`](../../core/dr-types/src/settings.rs#L377), [`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:1790`](../../ui/dr-ui/src/lib.rs#L1790), [`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:1790`](../../ui/dr-ui/src/lib.rs#L1790) |
-| 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:929`](../../core/dr-catalog/src/rating.rs#L929), [`core/dr-catalog/src/schema.rs:327`](../../core/dr-catalog/src/schema.rs#L327), [`core/dr-pipeline/src/sidecar.rs:137`](../../core/dr-pipeline/src/sidecar.rs#L137), [`core/dr-pipeline/src/sidecar.rs:2991`](../../core/dr-pipeline/src/sidecar.rs#L2991), [`core/dr-pipeline/src/sidecar.rs:660`](../../core/dr-pipeline/src/sidecar.rs#L660), [`core/dr-pipeline/src/sidecar.rs:735`](../../core/dr-pipeline/src/sidecar.rs#L735), [`core/dr-pipeline/src/sidecar.rs:96`](../../core/dr-pipeline/src/sidecar.rs#L96), [`ui/dr-ui/src/lib.rs:2691`](../../ui/dr-ui/src/lib.rs#L2691), [`ui/dr-ui/src/library/sidecar.rs:11`](../../ui/dr-ui/src/library/sidecar.rs#L11), [`ui/dr-ui/src/library/sidecar.rs:271`](../../ui/dr-ui/src/library/sidecar.rs#L271), [`ui/dr-ui/src/library/sidecar.rs:573`](../../ui/dr-ui/src/library/sidecar.rs#L573), [`ui/dr-ui/src/library/thumbnails_fetch.rs:504`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L504), [`ui/dr-ui/src/library_ui/controller.rs:625`](../../ui/dr-ui/src/library_ui/controller.rs#L625), [`ui/dr-ui/src/presets.rs:288`](../../ui/dr-ui/src/presets.rs#L288), [`ui/dr-ui/src/presets.rs:336`](../../ui/dr-ui/src/presets.rs#L336) |
-| 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:929`](../../core/dr-catalog/src/rating.rs#L929), [`core/dr-catalog/src/schema.rs:1125`](../../core/dr-catalog/src/schema.rs#L1125), [`core/dr-catalog/src/schema.rs:327`](../../core/dr-catalog/src/schema.rs#L327), [`core/dr-catalog/src/schema.rs:740`](../../core/dr-catalog/src/schema.rs#L740), [`core/dr-catalog/src/sync.rs:1`](../../core/dr-catalog/src/sync.rs#L1), [`core/dr-pipeline/src/sidecar.rs:192`](../../core/dr-pipeline/src/sidecar.rs#L192), [`core/dr-pipeline/src/sidecar.rs:219`](../../core/dr-pipeline/src/sidecar.rs#L219), [`core/dr-pipeline/src/sidecar.rs:2520`](../../core/dr-pipeline/src/sidecar.rs#L2520), [`core/dr-pipeline/src/sidecar.rs:2757`](../../core/dr-pipeline/src/sidecar.rs#L2757), [`core/dr-pipeline/src/sidecar.rs:2991`](../../core/dr-pipeline/src/sidecar.rs#L2991), [`core/dr-pipeline/src/sidecar.rs:395`](../../core/dr-pipeline/src/sidecar.rs#L395), [`core/dr-pipeline/src/sidecar.rs:493`](../../core/dr-pipeline/src/sidecar.rs#L493), [`core/dr-pipeline/src/sidecar.rs:660`](../../core/dr-pipeline/src/sidecar.rs#L660), [`core/dr-pipeline/src/sidecar.rs:710`](../../core/dr-pipeline/src/sidecar.rs#L710), [`core/dr-pipeline/src/sidecar.rs:735`](../../core/dr-pipeline/src/sidecar.rs#L735), [`core/dr-pipeline/src/spot.rs:245`](../../core/dr-pipeline/src/spot.rs#L245), [`core/dr-pipeline/tests/mask_sidecar.rs:1075`](../../core/dr-pipeline/tests/mask_sidecar.rs#L1075), [`core/dr-pipeline/tests/spot_sidecar.rs:1`](../../core/dr-pipeline/tests/spot_sidecar.rs#L1), [`core/dr-sync-nextcloud/src/lib.rs:139`](../../core/dr-sync-nextcloud/src/lib.rs#L139), [`core/dr-sync/src/scan.rs:31`](../../core/dr-sync/src/scan.rs#L31), [`core/dr-sync/src/scan.rs:56`](../../core/dr-sync/src/scan.rs#L56), [`core/dr-sync/src/scan.rs:926`](../../core/dr-sync/src/scan.rs#L926), [`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:1070`](../../ui/dr-ui/src/derived_sync.rs#L1070), [`ui/dr-ui/src/derived_sync.rs:613`](../../ui/dr-ui/src/derived_sync.rs#L613), [`ui/dr-ui/src/derived_sync.rs:642`](../../ui/dr-ui/src/derived_sync.rs#L642), [`ui/dr-ui/src/derived_sync.rs:675`](../../ui/dr-ui/src/derived_sync.rs#L675), [`ui/dr-ui/src/derived_sync.rs:821`](../../ui/dr-ui/src/derived_sync.rs#L821), [`ui/dr-ui/src/library/scan.rs:226`](../../ui/dr-ui/src/library/scan.rs#L226), [`ui/dr-ui/src/library/scan.rs:261`](../../ui/dr-ui/src/library/scan.rs#L261), [`ui/dr-ui/src/library/scan.rs:34`](../../ui/dr-ui/src/library/scan.rs#L34), [`ui/dr-ui/src/library/sidecar.rs:271`](../../ui/dr-ui/src/library/sidecar.rs#L271), [`ui/dr-ui/src/library/sidecar.rs:343`](../../ui/dr-ui/src/library/sidecar.rs#L343), [`ui/dr-ui/src/library/sidecar.rs:427`](../../ui/dr-ui/src/library/sidecar.rs#L427), [`ui/dr-ui/src/library/sidecar.rs:573`](../../ui/dr-ui/src/library/sidecar.rs#L573), [`ui/dr-ui/src/library/sidecar.rs:593`](../../ui/dr-ui/src/library/sidecar.rs#L593), [`ui/dr-ui/src/library/thumbnails_fetch.rs:504`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L504), [`ui/dr-ui/src/library_ui/open.rs:440`](../../ui/dr-ui/src/library_ui/open.rs#L440), [`ui/dr-ui/src/presets.rs:288`](../../ui/dr-ui/src/presets.rs#L288), [`ui/dr-ui/src/presets.rs:336`](../../ui/dr-ui/src/presets.rs#L336), [`ui/dr-ui/src/xmp_sync.rs:1`](../../ui/dr-ui/src/xmp_sync.rs#L1), [`ui/dr-ui/src/xmp_sync.rs:287`](../../ui/dr-ui/src/xmp_sync.rs#L287) |
-| 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:211`](../../core/dr-sync/src/scan.rs#L211), [`core/dr-sync/src/scan.rs:519`](../../core/dr-sync/src/scan.rs#L519), [`core/dr-sync/src/scan.rs:545`](../../core/dr-sync/src/scan.rs#L545), [`core/dr-sync/src/scan.rs:574`](../../core/dr-sync/src/scan.rs#L574), [`ui/dr-ui/src/library/scan.rs:126`](../../ui/dr-ui/src/library/scan.rs#L126), [`ui/dr-ui/src/library/scan.rs:179`](../../ui/dr-ui/src/library/scan.rs#L179), [`ui/dr-ui/src/library/scan.rs:210`](../../ui/dr-ui/src/library/scan.rs#L210), [`ui/dr-ui/src/library/scan.rs:605`](../../ui/dr-ui/src/library/scan.rs#L605), [`ui/dr-ui/src/library_ui/controller.rs:323`](../../ui/dr-ui/src/library_ui/controller.rs#L323), [`ui/dr-ui/src/library_ui/controller.rs:568`](../../ui/dr-ui/src/library_ui/controller.rs#L568), [`ui/dr-ui/src/library_ui/offline.rs:546`](../../ui/dr-ui/src/library_ui/offline.rs#L546), [`ui/dr-ui/src/library_ui/open.rs:411`](../../ui/dr-ui/src/library_ui/open.rs#L411), [`ui/dr-ui/src/library_ui/open.rs:507`](../../ui/dr-ui/src/library_ui/open.rs#L507) |
+| 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:120`](../../core/dr-sync-nextcloud/src/lib.rs#L120), [`ui/dr-ui/src/derived_sync.rs:1`](../../ui/dr-ui/src/derived_sync.rs#L1), [`ui/dr-ui/src/library/sweep.rs:557`](../../ui/dr-ui/src/library/sweep.rs#L557), [`ui/dr-ui/src/library_ui/sync.rs:368`](../../ui/dr-ui/src/library_ui/sync.rs#L368), [`ui/dr-ui/ui/settings.slint:435`](../../ui/dr-ui/ui/settings.slint#L435) |
+| 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:377`](../../core/dr-types/src/settings.rs#L377), [`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:1791`](../../ui/dr-ui/src/lib.rs#L1791), [`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:1791`](../../ui/dr-ui/src/lib.rs#L1791) |
+| 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:929`](../../core/dr-catalog/src/rating.rs#L929), [`core/dr-catalog/src/schema.rs:327`](../../core/dr-catalog/src/schema.rs#L327), [`core/dr-pipeline/src/sidecar.rs:137`](../../core/dr-pipeline/src/sidecar.rs#L137), [`core/dr-pipeline/src/sidecar.rs:2991`](../../core/dr-pipeline/src/sidecar.rs#L2991), [`core/dr-pipeline/src/sidecar.rs:660`](../../core/dr-pipeline/src/sidecar.rs#L660), [`core/dr-pipeline/src/sidecar.rs:735`](../../core/dr-pipeline/src/sidecar.rs#L735), [`core/dr-pipeline/src/sidecar.rs:96`](../../core/dr-pipeline/src/sidecar.rs#L96), [`ui/dr-ui/src/lib.rs:2692`](../../ui/dr-ui/src/lib.rs#L2692), [`ui/dr-ui/src/library/sidecar.rs:11`](../../ui/dr-ui/src/library/sidecar.rs#L11), [`ui/dr-ui/src/library/sidecar.rs:271`](../../ui/dr-ui/src/library/sidecar.rs#L271), [`ui/dr-ui/src/library/sidecar.rs:573`](../../ui/dr-ui/src/library/sidecar.rs#L573), [`ui/dr-ui/src/library/thumbnails_fetch.rs:504`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L504), [`ui/dr-ui/src/library_ui/controller.rs:625`](../../ui/dr-ui/src/library_ui/controller.rs#L625), [`ui/dr-ui/src/presets.rs:288`](../../ui/dr-ui/src/presets.rs#L288), [`ui/dr-ui/src/presets.rs:336`](../../ui/dr-ui/src/presets.rs#L336) |
+| 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:929`](../../core/dr-catalog/src/rating.rs#L929), [`core/dr-catalog/src/schema.rs:1125`](../../core/dr-catalog/src/schema.rs#L1125), [`core/dr-catalog/src/schema.rs:327`](../../core/dr-catalog/src/schema.rs#L327), [`core/dr-catalog/src/schema.rs:740`](../../core/dr-catalog/src/schema.rs#L740), [`core/dr-catalog/src/sync.rs:1`](../../core/dr-catalog/src/sync.rs#L1), [`core/dr-pipeline/src/sidecar.rs:192`](../../core/dr-pipeline/src/sidecar.rs#L192), [`core/dr-pipeline/src/sidecar.rs:219`](../../core/dr-pipeline/src/sidecar.rs#L219), [`core/dr-pipeline/src/sidecar.rs:2520`](../../core/dr-pipeline/src/sidecar.rs#L2520), [`core/dr-pipeline/src/sidecar.rs:2757`](../../core/dr-pipeline/src/sidecar.rs#L2757), [`core/dr-pipeline/src/sidecar.rs:2991`](../../core/dr-pipeline/src/sidecar.rs#L2991), [`core/dr-pipeline/src/sidecar.rs:395`](../../core/dr-pipeline/src/sidecar.rs#L395), [`core/dr-pipeline/src/sidecar.rs:493`](../../core/dr-pipeline/src/sidecar.rs#L493), [`core/dr-pipeline/src/sidecar.rs:660`](../../core/dr-pipeline/src/sidecar.rs#L660), [`core/dr-pipeline/src/sidecar.rs:710`](../../core/dr-pipeline/src/sidecar.rs#L710), [`core/dr-pipeline/src/sidecar.rs:735`](../../core/dr-pipeline/src/sidecar.rs#L735), [`core/dr-pipeline/src/spot.rs:245`](../../core/dr-pipeline/src/spot.rs#L245), [`core/dr-pipeline/tests/mask_sidecar.rs:1075`](../../core/dr-pipeline/tests/mask_sidecar.rs#L1075), [`core/dr-pipeline/tests/spot_sidecar.rs:1`](../../core/dr-pipeline/tests/spot_sidecar.rs#L1), [`core/dr-sync-nextcloud/src/lib.rs:139`](../../core/dr-sync-nextcloud/src/lib.rs#L139), [`core/dr-sync/src/scan.rs:31`](../../core/dr-sync/src/scan.rs#L31), [`core/dr-sync/src/scan.rs:56`](../../core/dr-sync/src/scan.rs#L56), [`core/dr-sync/src/scan.rs:926`](../../core/dr-sync/src/scan.rs#L926), [`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:1070`](../../ui/dr-ui/src/derived_sync.rs#L1070), [`ui/dr-ui/src/derived_sync.rs:613`](../../ui/dr-ui/src/derived_sync.rs#L613), [`ui/dr-ui/src/derived_sync.rs:642`](../../ui/dr-ui/src/derived_sync.rs#L642), [`ui/dr-ui/src/derived_sync.rs:675`](../../ui/dr-ui/src/derived_sync.rs#L675), [`ui/dr-ui/src/derived_sync.rs:821`](../../ui/dr-ui/src/derived_sync.rs#L821), [`ui/dr-ui/src/library/scan.rs:226`](../../ui/dr-ui/src/library/scan.rs#L226), [`ui/dr-ui/src/library/scan.rs:261`](../../ui/dr-ui/src/library/scan.rs#L261), [`ui/dr-ui/src/library/scan.rs:34`](../../ui/dr-ui/src/library/scan.rs#L34), [`ui/dr-ui/src/library/sidecar.rs:271`](../../ui/dr-ui/src/library/sidecar.rs#L271), [`ui/dr-ui/src/library/sidecar.rs:343`](../../ui/dr-ui/src/library/sidecar.rs#L343), [`ui/dr-ui/src/library/sidecar.rs:427`](../../ui/dr-ui/src/library/sidecar.rs#L427), [`ui/dr-ui/src/library/sidecar.rs:573`](../../ui/dr-ui/src/library/sidecar.rs#L573), [`ui/dr-ui/src/library/sidecar.rs:593`](../../ui/dr-ui/src/library/sidecar.rs#L593), [`ui/dr-ui/src/library/thumbnails_fetch.rs:504`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L504), [`ui/dr-ui/src/library_ui/open.rs:455`](../../ui/dr-ui/src/library_ui/open.rs#L455), [`ui/dr-ui/src/presets.rs:288`](../../ui/dr-ui/src/presets.rs#L288), [`ui/dr-ui/src/presets.rs:336`](../../ui/dr-ui/src/presets.rs#L336), [`ui/dr-ui/src/xmp_sync.rs:1`](../../ui/dr-ui/src/xmp_sync.rs#L1), [`ui/dr-ui/src/xmp_sync.rs:287`](../../ui/dr-ui/src/xmp_sync.rs#L287) |
+| 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:211`](../../core/dr-sync/src/scan.rs#L211), [`core/dr-sync/src/scan.rs:519`](../../core/dr-sync/src/scan.rs#L519), [`core/dr-sync/src/scan.rs:545`](../../core/dr-sync/src/scan.rs#L545), [`core/dr-sync/src/scan.rs:574`](../../core/dr-sync/src/scan.rs#L574), [`ui/dr-ui/src/library/scan.rs:126`](../../ui/dr-ui/src/library/scan.rs#L126), [`ui/dr-ui/src/library/scan.rs:179`](../../ui/dr-ui/src/library/scan.rs#L179), [`ui/dr-ui/src/library/scan.rs:210`](../../ui/dr-ui/src/library/scan.rs#L210), [`ui/dr-ui/src/library/scan.rs:605`](../../ui/dr-ui/src/library/scan.rs#L605), [`ui/dr-ui/src/library_ui/controller.rs:323`](../../ui/dr-ui/src/library_ui/controller.rs#L323), [`ui/dr-ui/src/library_ui/controller.rs:568`](../../ui/dr-ui/src/library_ui/controller.rs#L568), [`ui/dr-ui/src/library_ui/offline.rs:569`](../../ui/dr-ui/src/library_ui/offline.rs#L569), [`ui/dr-ui/src/library_ui/open.rs:426`](../../ui/dr-ui/src/library_ui/open.rs#L426), [`ui/dr-ui/src/library_ui/open.rs:524`](../../ui/dr-ui/src/library_ui/open.rs#L524) |
| 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:1057`](../../core/dr-gpu/src/adjust.rs#L1057), [`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/render.rs:519`](../../ui/dr-ui/src/develop/render.rs#L519), [`ui/dr-ui/src/identity_ui.rs:125`](../../ui/dr-ui/src/identity_ui.rs#L125), [`ui/dr-ui/src/lib.rs:1217`](../../ui/dr-ui/src/lib.rs#L1217), [`ui/dr-ui/src/lib.rs:1599`](../../ui/dr-ui/src/lib.rs#L1599), [`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:1057`](../../core/dr-gpu/src/adjust.rs#L1057), [`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/render.rs:519`](../../ui/dr-ui/src/develop/render.rs#L519), [`ui/dr-ui/src/identity_ui.rs:125`](../../ui/dr-ui/src/identity_ui.rs#L125), [`ui/dr-ui/src/lib.rs:1218`](../../ui/dr-ui/src/lib.rs#L1218), [`ui/dr-ui/src/lib.rs:1600`](../../ui/dr-ui/src/lib.rs#L1600), [`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:441`](../../apps/darkroom-android/src/lib.rs#L441) |
-| FR-PLAT-LIN-1 | [`core/dr-types/src/settings.rs:1`](../../core/dr-types/src/settings.rs#L1), [`platform/dr-plat/src/dirs.rs:1`](../../platform/dr-plat/src/dirs.rs#L1), [`platform/dr-plat/src/storage.rs:344`](../../platform/dr-plat/src/storage.rs#L344), [`ui/dr-ui/src/lib.rs:1385`](../../ui/dr-ui/src/lib.rs#L1385), [`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/dirs.rs:1`](../../platform/dr-plat/src/dirs.rs#L1), [`platform/dr-plat/src/storage.rs:344`](../../platform/dr-plat/src/storage.rs#L344), [`ui/dr-ui/src/lib.rs:1386`](../../ui/dr-ui/src/lib.rs#L1386), [`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-PLAT-WIN-1 | [`platform/dr-plat/src/dirs.rs:1`](../../platform/dr-plat/src/dirs.rs#L1) |
| FR-PLAT-WIN-2 | [`apps/darkroom-desktop/build.rs:1`](../../apps/darkroom-desktop/build.rs#L1), [`apps/darkroom-desktop/src/main.rs:6`](../../apps/darkroom-desktop/src/main.rs#L6), [`ui/dr-ui/src/launch_ui.rs:848`](../../ui/dr-ui/src/launch_ui.rs#L848) |
| FR-PLAT-WIN-3 | [`apps/darkroom-desktop/src/main.rs:19`](../../apps/darkroom-desktop/src/main.rs#L19) |
| FR-RAW-1 | [`core/dr-decode/src/lib.rs:259`](../../core/dr-decode/src/lib.rs#L259), [`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:155`](../../core/dr-decode/src/lib.rs#L155), [`core/dr-decode/src/lib.rs:546`](../../core/dr-decode/src/lib.rs#L546), [`core/dr-decode/src/locate.rs:1435`](../../core/dr-decode/src/locate.rs#L1435) |
-| FR-RAW-4 | [`core/dr-decode/src/error.rs:1`](../../core/dr-decode/src/error.rs#L1), [`core/dr-decode/src/error.rs:30`](../../core/dr-decode/src/error.rs#L30), [`ui/dr-ui/src/lib.rs:269`](../../ui/dr-ui/src/lib.rs#L269) |
+| FR-RAW-4 | [`core/dr-decode/src/error.rs:1`](../../core/dr-decode/src/error.rs#L1), [`core/dr-decode/src/error.rs:30`](../../core/dr-decode/src/error.rs#L30), [`ui/dr-ui/src/lib.rs:270`](../../ui/dr-ui/src/lib.rs#L270) |
| FR-RAW-5 | [`core/dr-decode/src/lib.rs:183`](../../core/dr-decode/src/lib.rs#L183), [`core/dr-gpu/src/demosaic.rs:34`](../../core/dr-gpu/src/demosaic.rs#L34), [`core/dr-gpu/src/demosaic.rs:734`](../../core/dr-gpu/src/demosaic.rs#L734), [`core/dr-gpu/src/demosaic.rs:813`](../../core/dr-gpu/src/demosaic.rs#L813), [`core/dr-gpu/src/demosaic.rs:937`](../../core/dr-gpu/src/demosaic.rs#L937) |
-| FR-UI-1 | [`core/dr-types/src/settings.rs:1377`](../../core/dr-types/src/settings.rs#L1377), [`core/dr-types/src/settings.rs:492`](../../core/dr-types/src/settings.rs#L492), [`core/dr-types/src/settings.rs:512`](../../core/dr-types/src/settings.rs#L512), [`ui/dr-ui/src/develop_ui.rs:204`](../../ui/dr-ui/src/develop_ui.rs#L204), [`ui/dr-ui/src/lib.rs:109`](../../ui/dr-ui/src/lib.rs#L109), [`ui/dr-ui/src/lib.rs:124`](../../ui/dr-ui/src/lib.rs#L124), [`ui/dr-ui/src/lib.rs:146`](../../ui/dr-ui/src/lib.rs#L146), [`ui/dr-ui/src/lib.rs:3201`](../../ui/dr-ui/src/lib.rs#L3201), [`ui/dr-ui/src/lib.rs:3220`](../../ui/dr-ui/src/lib.rs#L3220), [`ui/dr-ui/src/lib.rs:3247`](../../ui/dr-ui/src/lib.rs#L3247), [`ui/dr-ui/src/lib.rs:3298`](../../ui/dr-ui/src/lib.rs#L3298), [`ui/dr-ui/src/lib.rs:3331`](../../ui/dr-ui/src/lib.rs#L3331), [`ui/dr-ui/src/masks_ui.rs:1537`](../../ui/dr-ui/src/masks_ui.rs#L1537), [`ui/dr-ui/src/settings_ui.rs:179`](../../ui/dr-ui/src/settings_ui.rs#L179), [`ui/dr-ui/ui/adjust.slint:974`](../../ui/dr-ui/ui/adjust.slint#L974), [`ui/dr-ui/ui/app.slint:2798`](../../ui/dr-ui/ui/app.slint#L2798), [`ui/dr-ui/ui/app.slint:862`](../../ui/dr-ui/ui/app.slint#L862), [`ui/dr-ui/ui/app.slint:966`](../../ui/dr-ui/ui/app.slint#L966), [`ui/dr-ui/ui/identity.slint:246`](../../ui/dr-ui/ui/identity.slint#L246), [`ui/dr-ui/ui/library.slint:1076`](../../ui/dr-ui/ui/library.slint#L1076), [`ui/dr-ui/ui/settings.slint:122`](../../ui/dr-ui/ui/settings.slint#L122), [`ui/dr-ui/ui/settings.slint:681`](../../ui/dr-ui/ui/settings.slint#L681), [`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/controller.rs:45`](../../ui/dr-ui/src/collections_ui/controller.rs#L45), [`ui/dr-ui/src/collections_ui/controller.rs:83`](../../ui/dr-ui/src/collections_ui/controller.rs#L83), [`ui/dr-ui/src/collections_ui/drag.rs:246`](../../ui/dr-ui/src/collections_ui/drag.rs#L246), [`ui/dr-ui/src/collections_ui/drag.rs:256`](../../ui/dr-ui/src/collections_ui/drag.rs#L256), [`ui/dr-ui/src/collections_ui/press.rs:452`](../../ui/dr-ui/src/collections_ui/press.rs#L452), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:119`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L119), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:136`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L136), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:405`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L405), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:284`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L284), [`ui/dr-ui/src/gestures.rs:1`](../../ui/dr-ui/src/gestures.rs#L1), [`ui/dr-ui/src/lib.rs:109`](../../ui/dr-ui/src/lib.rs#L109), [`ui/dr-ui/src/library_ui/filter_bar.rs:274`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L274), [`ui/dr-ui/src/library_ui/window.rs:865`](../../ui/dr-ui/src/library_ui/window.rs#L865), [`ui/dr-ui/ui/app.slint:111`](../../ui/dr-ui/ui/app.slint#L111), [`ui/dr-ui/ui/app.slint:586`](../../ui/dr-ui/ui/app.slint#L586), [`ui/dr-ui/ui/app.slint:950`](../../ui/dr-ui/ui/app.slint#L950), [`ui/dr-ui/ui/collections.slint:1253`](../../ui/dr-ui/ui/collections.slint#L1253), [`ui/dr-ui/ui/controls.slint:626`](../../ui/dr-ui/ui/controls.slint#L626), [`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:2628`](../../ui/dr-ui/ui/library.slint#L2628), [`ui/dr-ui/ui/library.slint:4377`](../../ui/dr-ui/ui/library.slint#L4377), [`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:136`](../../ui/dr-ui/ui/settings.slint#L136) |
-| FR-UI-3 | [`ui/dr-ui/src/collections_ui/controller.rs:138`](../../ui/dr-ui/src/collections_ui/controller.rs#L138), [`ui/dr-ui/src/collections_ui/controller.rs:343`](../../ui/dr-ui/src/collections_ui/controller.rs#L343), [`ui/dr-ui/src/collections_ui/controller.rs:356`](../../ui/dr-ui/src/collections_ui/controller.rs#L356), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:284`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L284), [`ui/dr-ui/src/develop/masks.rs:360`](../../ui/dr-ui/src/develop/masks.rs#L360), [`ui/dr-ui/src/develop/repairs.rs:49`](../../ui/dr-ui/src/develop/repairs.rs#L49), [`ui/dr-ui/src/library_ui/grid.rs:168`](../../ui/dr-ui/src/library_ui/grid.rs#L168), [`ui/dr-ui/src/masks_ui.rs:1629`](../../ui/dr-ui/src/masks_ui.rs#L1629), [`ui/dr-ui/src/masks_ui.rs:1651`](../../ui/dr-ui/src/masks_ui.rs#L1651), [`ui/dr-ui/src/masks_ui.rs:339`](../../ui/dr-ui/src/masks_ui.rs#L339), [`ui/dr-ui/src/spots_ui.rs:19`](../../ui/dr-ui/src/spots_ui.rs#L19), [`ui/dr-ui/ui/app.slint:2341`](../../ui/dr-ui/ui/app.slint#L2341), [`ui/dr-ui/ui/collections.slint:1127`](../../ui/dr-ui/ui/collections.slint#L1127), [`ui/dr-ui/ui/collections.slint:4`](../../ui/dr-ui/ui/collections.slint#L4), [`ui/dr-ui/ui/collections.slint:75`](../../ui/dr-ui/ui/collections.slint#L75), [`ui/dr-ui/ui/collections.slint:877`](../../ui/dr-ui/ui/collections.slint#L877), [`ui/dr-ui/ui/masks.slint:1216`](../../ui/dr-ui/ui/masks.slint#L1216), [`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/controller.rs:138`](../../ui/dr-ui/src/collections_ui/controller.rs#L138), [`ui/dr-ui/src/collections_ui/controller.rs:343`](../../ui/dr-ui/src/collections_ui/controller.rs#L343), [`ui/dr-ui/src/collections_ui/controller.rs:356`](../../ui/dr-ui/src/collections_ui/controller.rs#L356), [`ui/dr-ui/src/collections_ui/controller.rs:45`](../../ui/dr-ui/src/collections_ui/controller.rs#L45), [`ui/dr-ui/src/collections_ui/controller.rs:46`](../../ui/dr-ui/src/collections_ui/controller.rs#L46), [`ui/dr-ui/src/collections_ui/controller.rs:55`](../../ui/dr-ui/src/collections_ui/controller.rs#L55), [`ui/dr-ui/src/collections_ui/controller.rs:83`](../../ui/dr-ui/src/collections_ui/controller.rs#L83), [`ui/dr-ui/src/collections_ui/drag.rs:246`](../../ui/dr-ui/src/collections_ui/drag.rs#L246), [`ui/dr-ui/src/collections_ui/drag.rs:256`](../../ui/dr-ui/src/collections_ui/drag.rs#L256), [`ui/dr-ui/src/collections_ui/press.rs:257`](../../ui/dr-ui/src/collections_ui/press.rs#L257), [`ui/dr-ui/src/collections_ui/press.rs:277`](../../ui/dr-ui/src/collections_ui/press.rs#L277), [`ui/dr-ui/src/collections_ui/press.rs:452`](../../ui/dr-ui/src/collections_ui/press.rs#L452), [`ui/dr-ui/src/collections_ui/press.rs:489`](../../ui/dr-ui/src/collections_ui/press.rs#L489), [`ui/dr-ui/src/collections_ui/press.rs:53`](../../ui/dr-ui/src/collections_ui/press.rs#L53), [`ui/dr-ui/src/collections_ui/tree_sync.rs:337`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L337), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:119`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L119), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:136`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L136), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:256`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L256), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:405`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L405), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:432`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L432), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:561`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L561), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:284`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L284), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:341`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L341), [`ui/dr-ui/src/develop/framing.rs:444`](../../ui/dr-ui/src/develop/framing.rs#L444), [`ui/dr-ui/src/develop/framing.rs:469`](../../ui/dr-ui/src/develop/framing.rs#L469), [`ui/dr-ui/src/develop/framing.rs:480`](../../ui/dr-ui/src/develop/framing.rs#L480), [`ui/dr-ui/src/develop/framing.rs:494`](../../ui/dr-ui/src/develop/framing.rs#L494), [`ui/dr-ui/src/develop/framing.rs:668`](../../ui/dr-ui/src/develop/framing.rs#L668), [`ui/dr-ui/src/develop/framing.rs:699`](../../ui/dr-ui/src/develop/framing.rs#L699), [`ui/dr-ui/src/develop/framing.rs:720`](../../ui/dr-ui/src/develop/framing.rs#L720), [`ui/dr-ui/src/develop_ui.rs:804`](../../ui/dr-ui/src/develop_ui.rs#L804), [`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:1284`](../../ui/dr-ui/src/lib.rs#L1284), [`ui/dr-ui/src/lib.rs:1572`](../../ui/dr-ui/src/lib.rs#L1572), [`ui/dr-ui/src/lib.rs:2573`](../../ui/dr-ui/src/lib.rs#L2573), [`ui/dr-ui/src/lib.rs:2792`](../../ui/dr-ui/src/lib.rs#L2792), [`ui/dr-ui/src/lib.rs:2852`](../../ui/dr-ui/src/lib.rs#L2852), [`ui/dr-ui/src/lib.rs:3011`](../../ui/dr-ui/src/lib.rs#L3011), [`ui/dr-ui/src/lib.rs:3451`](../../ui/dr-ui/src/lib.rs#L3451), [`ui/dr-ui/src/lib.rs:461`](../../ui/dr-ui/src/lib.rs#L461), [`ui/dr-ui/src/lib.rs:490`](../../ui/dr-ui/src/lib.rs#L490), [`ui/dr-ui/src/library/thumbnails_fetch.rs:711`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L711), [`ui/dr-ui/src/library/thumbnails_fetch.rs:726`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L726), [`ui/dr-ui/src/library_ui/controller.rs:382`](../../ui/dr-ui/src/library_ui/controller.rs#L382), [`ui/dr-ui/src/library_ui/controller.rs:522`](../../ui/dr-ui/src/library_ui/controller.rs#L522), [`ui/dr-ui/src/library_ui/controller.rs:599`](../../ui/dr-ui/src/library_ui/controller.rs#L599), [`ui/dr-ui/src/library_ui/filter_bar.rs:415`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L415), [`ui/dr-ui/src/library_ui/grid.rs:168`](../../ui/dr-ui/src/library_ui/grid.rs#L168), [`ui/dr-ui/src/library_ui/grid.rs:180`](../../ui/dr-ui/src/library_ui/grid.rs#L180), [`ui/dr-ui/src/library_ui/grid.rs:250`](../../ui/dr-ui/src/library_ui/grid.rs#L250), [`ui/dr-ui/src/library_ui/grid.rs:382`](../../ui/dr-ui/src/library_ui/grid.rs#L382), [`ui/dr-ui/src/library_ui/grid.rs:410`](../../ui/dr-ui/src/library_ui/grid.rs#L410), [`ui/dr-ui/src/settings_ui.rs:157`](../../ui/dr-ui/src/settings_ui.rs#L157), [`ui/dr-ui/src/settings_ui.rs:542`](../../ui/dr-ui/src/settings_ui.rs#L542), [`ui/dr-ui/ui/app.slint:2036`](../../ui/dr-ui/ui/app.slint#L2036), [`ui/dr-ui/ui/app.slint:211`](../../ui/dr-ui/ui/app.slint#L211), [`ui/dr-ui/ui/app.slint:2158`](../../ui/dr-ui/ui/app.slint#L2158), [`ui/dr-ui/ui/app.slint:2565`](../../ui/dr-ui/ui/app.slint#L2565), [`ui/dr-ui/ui/app.slint:2698`](../../ui/dr-ui/ui/app.slint#L2698), [`ui/dr-ui/ui/app.slint:3169`](../../ui/dr-ui/ui/app.slint#L3169), [`ui/dr-ui/ui/app.slint:562`](../../ui/dr-ui/ui/app.slint#L562), [`ui/dr-ui/ui/app.slint:591`](../../ui/dr-ui/ui/app.slint#L591), [`ui/dr-ui/ui/app.slint:670`](../../ui/dr-ui/ui/app.slint#L670), [`ui/dr-ui/ui/collections.slint:1253`](../../ui/dr-ui/ui/collections.slint#L1253), [`ui/dr-ui/ui/collections.slint:75`](../../ui/dr-ui/ui/collections.slint#L75), [`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:2628`](../../ui/dr-ui/ui/library.slint#L2628), [`ui/dr-ui/ui/library.slint:4231`](../../ui/dr-ui/ui/library.slint#L4231), [`ui/dr-ui/ui/library.slint:4318`](../../ui/dr-ui/ui/library.slint#L4318), [`ui/dr-ui/ui/library.slint:4377`](../../ui/dr-ui/ui/library.slint#L4377), [`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), [`ui/dr-ui/ui/settings.slint:114`](../../ui/dr-ui/ui/settings.slint#L114), [`ui/dr-ui/ui/settings.slint:656`](../../ui/dr-ui/ui/settings.slint#L656) |
-| FR-UI-5 | [`ui/dr-ui/src/collections_ui/mod.rs:1`](../../ui/dr-ui/src/collections_ui/mod.rs#L1), [`ui/dr-ui/src/develop_ui.rs:849`](../../ui/dr-ui/src/develop_ui.rs#L849), [`ui/dr-ui/src/lib.rs:3395`](../../ui/dr-ui/src/lib.rs#L3395), [`ui/dr-ui/src/lib.rs:3602`](../../ui/dr-ui/src/lib.rs#L3602), [`ui/dr-ui/src/masks_ui.rs:1584`](../../ui/dr-ui/src/masks_ui.rs#L1584), [`ui/dr-ui/ui/app.slint:2525`](../../ui/dr-ui/ui/app.slint#L2525), [`ui/dr-ui/ui/app.slint:2565`](../../ui/dr-ui/ui/app.slint#L2565), [`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-1 | [`core/dr-types/src/settings.rs:1377`](../../core/dr-types/src/settings.rs#L1377), [`core/dr-types/src/settings.rs:492`](../../core/dr-types/src/settings.rs#L492), [`core/dr-types/src/settings.rs:512`](../../core/dr-types/src/settings.rs#L512), [`ui/dr-ui/src/develop_ui.rs:204`](../../ui/dr-ui/src/develop_ui.rs#L204), [`ui/dr-ui/src/lib.rs:110`](../../ui/dr-ui/src/lib.rs#L110), [`ui/dr-ui/src/lib.rs:125`](../../ui/dr-ui/src/lib.rs#L125), [`ui/dr-ui/src/lib.rs:147`](../../ui/dr-ui/src/lib.rs#L147), [`ui/dr-ui/src/lib.rs:3202`](../../ui/dr-ui/src/lib.rs#L3202), [`ui/dr-ui/src/lib.rs:3221`](../../ui/dr-ui/src/lib.rs#L3221), [`ui/dr-ui/src/lib.rs:3248`](../../ui/dr-ui/src/lib.rs#L3248), [`ui/dr-ui/src/lib.rs:3299`](../../ui/dr-ui/src/lib.rs#L3299), [`ui/dr-ui/src/lib.rs:3332`](../../ui/dr-ui/src/lib.rs#L3332), [`ui/dr-ui/src/masks_ui.rs:1537`](../../ui/dr-ui/src/masks_ui.rs#L1537), [`ui/dr-ui/src/settings_ui.rs:179`](../../ui/dr-ui/src/settings_ui.rs#L179), [`ui/dr-ui/ui/adjust.slint:974`](../../ui/dr-ui/ui/adjust.slint#L974), [`ui/dr-ui/ui/app.slint:2533`](../../ui/dr-ui/ui/app.slint#L2533), [`ui/dr-ui/ui/app.slint:605`](../../ui/dr-ui/ui/app.slint#L605), [`ui/dr-ui/ui/app.slint:709`](../../ui/dr-ui/ui/app.slint#L709), [`ui/dr-ui/ui/identity.slint:246`](../../ui/dr-ui/ui/identity.slint#L246), [`ui/dr-ui/ui/library.slint:1346`](../../ui/dr-ui/ui/library.slint#L1346), [`ui/dr-ui/ui/settings.slint:122`](../../ui/dr-ui/ui/settings.slint#L122), [`ui/dr-ui/ui/settings.slint:681`](../../ui/dr-ui/ui/settings.slint#L681), [`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/controller.rs:45`](../../ui/dr-ui/src/collections_ui/controller.rs#L45), [`ui/dr-ui/src/collections_ui/controller.rs:83`](../../ui/dr-ui/src/collections_ui/controller.rs#L83), [`ui/dr-ui/src/collections_ui/drag.rs:246`](../../ui/dr-ui/src/collections_ui/drag.rs#L246), [`ui/dr-ui/src/collections_ui/drag.rs:256`](../../ui/dr-ui/src/collections_ui/drag.rs#L256), [`ui/dr-ui/src/collections_ui/press.rs:453`](../../ui/dr-ui/src/collections_ui/press.rs#L453), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:121`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L121), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:138`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L138), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:415`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L415), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:287`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L287), [`ui/dr-ui/src/gestures.rs:1`](../../ui/dr-ui/src/gestures.rs#L1), [`ui/dr-ui/src/lib.rs:110`](../../ui/dr-ui/src/lib.rs#L110), [`ui/dr-ui/src/library_ui/filter_bar.rs:295`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L295), [`ui/dr-ui/src/library_ui/window.rs:873`](../../ui/dr-ui/src/library_ui/window.rs#L873), [`ui/dr-ui/ui/app.slint:112`](../../ui/dr-ui/ui/app.slint#L112), [`ui/dr-ui/ui/app.slint:693`](../../ui/dr-ui/ui/app.slint#L693), [`ui/dr-ui/ui/collections.slint:1253`](../../ui/dr-ui/ui/collections.slint#L1253), [`ui/dr-ui/ui/controls.slint:626`](../../ui/dr-ui/ui/controls.slint#L626), [`ui/dr-ui/ui/gestures.slint:1`](../../ui/dr-ui/ui/gestures.slint#L1), [`ui/dr-ui/ui/library.slint:1235`](../../ui/dr-ui/ui/library.slint#L1235), [`ui/dr-ui/ui/library.slint:1268`](../../ui/dr-ui/ui/library.slint#L1268), [`ui/dr-ui/ui/library.slint:1557`](../../ui/dr-ui/ui/library.slint#L1557), [`ui/dr-ui/ui/library.slint:1564`](../../ui/dr-ui/ui/library.slint#L1564), [`ui/dr-ui/ui/library.slint:1661`](../../ui/dr-ui/ui/library.slint#L1661), [`ui/dr-ui/ui/library.slint:2898`](../../ui/dr-ui/ui/library.slint#L2898), [`ui/dr-ui/ui/library.slint:4647`](../../ui/dr-ui/ui/library.slint#L4647), [`ui/dr-ui/ui/library.slint:554`](../../ui/dr-ui/ui/library.slint#L554), [`ui/dr-ui/ui/presets.slint:19`](../../ui/dr-ui/ui/presets.slint#L19), [`ui/dr-ui/ui/settings.slint:136`](../../ui/dr-ui/ui/settings.slint#L136) |
+| FR-UI-3 | [`ui/dr-ui/src/collections_ui/controller.rs:138`](../../ui/dr-ui/src/collections_ui/controller.rs#L138), [`ui/dr-ui/src/collections_ui/controller.rs:343`](../../ui/dr-ui/src/collections_ui/controller.rs#L343), [`ui/dr-ui/src/collections_ui/controller.rs:356`](../../ui/dr-ui/src/collections_ui/controller.rs#L356), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:287`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L287), [`ui/dr-ui/src/develop/masks.rs:360`](../../ui/dr-ui/src/develop/masks.rs#L360), [`ui/dr-ui/src/develop/repairs.rs:49`](../../ui/dr-ui/src/develop/repairs.rs#L49), [`ui/dr-ui/src/library_ui/grid.rs:168`](../../ui/dr-ui/src/library_ui/grid.rs#L168), [`ui/dr-ui/src/masks_ui.rs:1629`](../../ui/dr-ui/src/masks_ui.rs#L1629), [`ui/dr-ui/src/masks_ui.rs:1651`](../../ui/dr-ui/src/masks_ui.rs#L1651), [`ui/dr-ui/src/masks_ui.rs:339`](../../ui/dr-ui/src/masks_ui.rs#L339), [`ui/dr-ui/src/spots_ui.rs:19`](../../ui/dr-ui/src/spots_ui.rs#L19), [`ui/dr-ui/ui/app.slint:2076`](../../ui/dr-ui/ui/app.slint#L2076), [`ui/dr-ui/ui/collections.slint:1127`](../../ui/dr-ui/ui/collections.slint#L1127), [`ui/dr-ui/ui/collections.slint:4`](../../ui/dr-ui/ui/collections.slint#L4), [`ui/dr-ui/ui/collections.slint:75`](../../ui/dr-ui/ui/collections.slint#L75), [`ui/dr-ui/ui/collections.slint:877`](../../ui/dr-ui/ui/collections.slint#L877), [`ui/dr-ui/ui/masks.slint:1216`](../../ui/dr-ui/ui/masks.slint#L1216), [`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/controller.rs:138`](../../ui/dr-ui/src/collections_ui/controller.rs#L138), [`ui/dr-ui/src/collections_ui/controller.rs:343`](../../ui/dr-ui/src/collections_ui/controller.rs#L343), [`ui/dr-ui/src/collections_ui/controller.rs:356`](../../ui/dr-ui/src/collections_ui/controller.rs#L356), [`ui/dr-ui/src/collections_ui/controller.rs:45`](../../ui/dr-ui/src/collections_ui/controller.rs#L45), [`ui/dr-ui/src/collections_ui/controller.rs:46`](../../ui/dr-ui/src/collections_ui/controller.rs#L46), [`ui/dr-ui/src/collections_ui/controller.rs:55`](../../ui/dr-ui/src/collections_ui/controller.rs#L55), [`ui/dr-ui/src/collections_ui/controller.rs:83`](../../ui/dr-ui/src/collections_ui/controller.rs#L83), [`ui/dr-ui/src/collections_ui/drag.rs:246`](../../ui/dr-ui/src/collections_ui/drag.rs#L246), [`ui/dr-ui/src/collections_ui/drag.rs:256`](../../ui/dr-ui/src/collections_ui/drag.rs#L256), [`ui/dr-ui/src/collections_ui/press.rs:258`](../../ui/dr-ui/src/collections_ui/press.rs#L258), [`ui/dr-ui/src/collections_ui/press.rs:278`](../../ui/dr-ui/src/collections_ui/press.rs#L278), [`ui/dr-ui/src/collections_ui/press.rs:453`](../../ui/dr-ui/src/collections_ui/press.rs#L453), [`ui/dr-ui/src/collections_ui/press.rs:490`](../../ui/dr-ui/src/collections_ui/press.rs#L490), [`ui/dr-ui/src/collections_ui/press.rs:54`](../../ui/dr-ui/src/collections_ui/press.rs#L54), [`ui/dr-ui/src/collections_ui/tree_sync.rs:339`](../../ui/dr-ui/src/collections_ui/tree_sync.rs#L339), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:121`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L121), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:138`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L138), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:264`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L264), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:415`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L415), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:444`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L444), [`ui/dr-ui/src/collections_ui/wiring_grid.rs:577`](../../ui/dr-ui/src/collections_ui/wiring_grid.rs#L577), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:287`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L287), [`ui/dr-ui/src/collections_ui/wiring_tree.rs:344`](../../ui/dr-ui/src/collections_ui/wiring_tree.rs#L344), [`ui/dr-ui/src/develop/framing.rs:444`](../../ui/dr-ui/src/develop/framing.rs#L444), [`ui/dr-ui/src/develop/framing.rs:469`](../../ui/dr-ui/src/develop/framing.rs#L469), [`ui/dr-ui/src/develop/framing.rs:480`](../../ui/dr-ui/src/develop/framing.rs#L480), [`ui/dr-ui/src/develop/framing.rs:494`](../../ui/dr-ui/src/develop/framing.rs#L494), [`ui/dr-ui/src/develop/framing.rs:668`](../../ui/dr-ui/src/develop/framing.rs#L668), [`ui/dr-ui/src/develop/framing.rs:699`](../../ui/dr-ui/src/develop/framing.rs#L699), [`ui/dr-ui/src/develop/framing.rs:720`](../../ui/dr-ui/src/develop/framing.rs#L720), [`ui/dr-ui/src/develop_ui.rs:812`](../../ui/dr-ui/src/develop_ui.rs#L812), [`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:1285`](../../ui/dr-ui/src/lib.rs#L1285), [`ui/dr-ui/src/lib.rs:1573`](../../ui/dr-ui/src/lib.rs#L1573), [`ui/dr-ui/src/lib.rs:2574`](../../ui/dr-ui/src/lib.rs#L2574), [`ui/dr-ui/src/lib.rs:2793`](../../ui/dr-ui/src/lib.rs#L2793), [`ui/dr-ui/src/lib.rs:2853`](../../ui/dr-ui/src/lib.rs#L2853), [`ui/dr-ui/src/lib.rs:3012`](../../ui/dr-ui/src/lib.rs#L3012), [`ui/dr-ui/src/lib.rs:3452`](../../ui/dr-ui/src/lib.rs#L3452), [`ui/dr-ui/src/lib.rs:462`](../../ui/dr-ui/src/lib.rs#L462), [`ui/dr-ui/src/lib.rs:491`](../../ui/dr-ui/src/lib.rs#L491), [`ui/dr-ui/src/library/thumbnails_fetch.rs:711`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L711), [`ui/dr-ui/src/library/thumbnails_fetch.rs:726`](../../ui/dr-ui/src/library/thumbnails_fetch.rs#L726), [`ui/dr-ui/src/library_ui/controller.rs:382`](../../ui/dr-ui/src/library_ui/controller.rs#L382), [`ui/dr-ui/src/library_ui/controller.rs:522`](../../ui/dr-ui/src/library_ui/controller.rs#L522), [`ui/dr-ui/src/library_ui/controller.rs:599`](../../ui/dr-ui/src/library_ui/controller.rs#L599), [`ui/dr-ui/src/library_ui/filter_bar.rs:444`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L444), [`ui/dr-ui/src/library_ui/grid.rs:168`](../../ui/dr-ui/src/library_ui/grid.rs#L168), [`ui/dr-ui/src/library_ui/grid.rs:182`](../../ui/dr-ui/src/library_ui/grid.rs#L182), [`ui/dr-ui/src/library_ui/grid.rs:256`](../../ui/dr-ui/src/library_ui/grid.rs#L256), [`ui/dr-ui/src/library_ui/grid.rs:393`](../../ui/dr-ui/src/library_ui/grid.rs#L393), [`ui/dr-ui/src/library_ui/grid.rs:423`](../../ui/dr-ui/src/library_ui/grid.rs#L423), [`ui/dr-ui/src/settings_ui.rs:157`](../../ui/dr-ui/src/settings_ui.rs#L157), [`ui/dr-ui/src/settings_ui.rs:542`](../../ui/dr-ui/src/settings_ui.rs#L542), [`ui/dr-ui/ui/app.slint:1772`](../../ui/dr-ui/ui/app.slint#L1772), [`ui/dr-ui/ui/app.slint:1894`](../../ui/dr-ui/ui/app.slint#L1894), [`ui/dr-ui/ui/app.slint:212`](../../ui/dr-ui/ui/app.slint#L212), [`ui/dr-ui/ui/app.slint:2300`](../../ui/dr-ui/ui/app.slint#L2300), [`ui/dr-ui/ui/app.slint:2433`](../../ui/dr-ui/ui/app.slint#L2433), [`ui/dr-ui/ui/app.slint:2904`](../../ui/dr-ui/ui/app.slint#L2904), [`ui/dr-ui/ui/collections.slint:1253`](../../ui/dr-ui/ui/collections.slint#L1253), [`ui/dr-ui/ui/collections.slint:75`](../../ui/dr-ui/ui/collections.slint#L75), [`ui/dr-ui/ui/gestures.slint:1`](../../ui/dr-ui/ui/gestures.slint#L1), [`ui/dr-ui/ui/library.slint:1235`](../../ui/dr-ui/ui/library.slint#L1235), [`ui/dr-ui/ui/library.slint:1262`](../../ui/dr-ui/ui/library.slint#L1262), [`ui/dr-ui/ui/library.slint:1268`](../../ui/dr-ui/ui/library.slint#L1268), [`ui/dr-ui/ui/library.slint:1323`](../../ui/dr-ui/ui/library.slint#L1323), [`ui/dr-ui/ui/library.slint:1532`](../../ui/dr-ui/ui/library.slint#L1532), [`ui/dr-ui/ui/library.slint:1557`](../../ui/dr-ui/ui/library.slint#L1557), [`ui/dr-ui/ui/library.slint:1564`](../../ui/dr-ui/ui/library.slint#L1564), [`ui/dr-ui/ui/library.slint:1597`](../../ui/dr-ui/ui/library.slint#L1597), [`ui/dr-ui/ui/library.slint:1654`](../../ui/dr-ui/ui/library.slint#L1654), [`ui/dr-ui/ui/library.slint:1661`](../../ui/dr-ui/ui/library.slint#L1661), [`ui/dr-ui/ui/library.slint:2898`](../../ui/dr-ui/ui/library.slint#L2898), [`ui/dr-ui/ui/library.slint:4501`](../../ui/dr-ui/ui/library.slint#L4501), [`ui/dr-ui/ui/library.slint:4588`](../../ui/dr-ui/ui/library.slint#L4588), [`ui/dr-ui/ui/library.slint:4647`](../../ui/dr-ui/ui/library.slint#L4647), [`ui/dr-ui/ui/library.slint:549`](../../ui/dr-ui/ui/library.slint#L549), [`ui/dr-ui/ui/library.slint:559`](../../ui/dr-ui/ui/library.slint#L559), [`ui/dr-ui/ui/library.slint:691`](../../ui/dr-ui/ui/library.slint#L691), [`ui/dr-ui/ui/settings.slint:114`](../../ui/dr-ui/ui/settings.slint#L114), [`ui/dr-ui/ui/settings.slint:656`](../../ui/dr-ui/ui/settings.slint#L656) |
+| FR-UI-5 | [`ui/dr-ui/src/collections_ui/mod.rs:1`](../../ui/dr-ui/src/collections_ui/mod.rs#L1), [`ui/dr-ui/src/develop_ui.rs:857`](../../ui/dr-ui/src/develop_ui.rs#L857), [`ui/dr-ui/src/lib.rs:3396`](../../ui/dr-ui/src/lib.rs#L3396), [`ui/dr-ui/src/lib.rs:3603`](../../ui/dr-ui/src/lib.rs#L3603), [`ui/dr-ui/src/masks_ui.rs:1584`](../../ui/dr-ui/src/masks_ui.rs#L1584), [`ui/dr-ui/ui/app.slint:2260`](../../ui/dr-ui/ui/app.slint#L2260), [`ui/dr-ui/ui/app.slint:2300`](../../ui/dr-ui/ui/app.slint#L2300), [`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:492`](../../core/dr-types/src/settings.rs#L492), [`ui/dr-ui/src/develop/rows.rs:118`](../../ui/dr-ui/src/develop/rows.rs#L118), [`ui/dr-ui/src/lib.rs:3220`](../../ui/dr-ui/src/lib.rs#L3220), [`ui/dr-ui/ui/adjust.slint:974`](../../ui/dr-ui/ui/adjust.slint#L974), [`ui/dr-ui/ui/app.slint:2281`](../../ui/dr-ui/ui/app.slint#L2281), [`ui/dr-ui/ui/settings.slint:681`](../../ui/dr-ui/ui/settings.slint#L681), [`ui/dr-ui/ui/toolrail.slint:89`](../../ui/dr-ui/ui/toolrail.slint#L89) |
-| FR-UI-8 | [`core/dr-catalog/src/collections.rs:654`](../../core/dr-catalog/src/collections.rs#L654), [`core/dr-catalog/src/collections.rs:675`](../../core/dr-catalog/src/collections.rs#L675), [`core/dr-types/src/place.rs:1`](../../core/dr-types/src/place.rs#L1), [`ui/dr-ui/src/derived_sync.rs:216`](../../ui/dr-ui/src/derived_sync.rs#L216), [`ui/dr-ui/src/derived_sync.rs:81`](../../ui/dr-ui/src/derived_sync.rs#L81), [`ui/dr-ui/src/derived_sync.rs:894`](../../ui/dr-ui/src/derived_sync.rs#L894), [`ui/dr-ui/src/derived_sync.rs:904`](../../ui/dr-ui/src/derived_sync.rs#L904), [`ui/dr-ui/src/derived_sync.rs:986`](../../ui/dr-ui/src/derived_sync.rs#L986), [`ui/dr-ui/src/library/cells.rs:274`](../../ui/dr-ui/src/library/cells.rs#L274), [`ui/dr-ui/src/library/cells.rs:553`](../../ui/dr-ui/src/library/cells.rs#L553), [`ui/dr-ui/src/library/cells.rs:619`](../../ui/dr-ui/src/library/cells.rs#L619), [`ui/dr-ui/src/library/paths.rs:22`](../../ui/dr-ui/src/library/paths.rs#L22), [`ui/dr-ui/src/library_ui/controller.rs:189`](../../ui/dr-ui/src/library_ui/controller.rs#L189), [`ui/dr-ui/src/library_ui/controller.rs:924`](../../ui/dr-ui/src/library_ui/controller.rs#L924), [`ui/dr-ui/src/library_ui/filter_bar.rs:631`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L631), [`ui/dr-ui/src/library_ui/grid.rs:201`](../../ui/dr-ui/src/library_ui/grid.rs#L201), [`ui/dr-ui/src/library_ui/grid.rs:241`](../../ui/dr-ui/src/library_ui/grid.rs#L241), [`ui/dr-ui/src/library_ui/grid.rs:270`](../../ui/dr-ui/src/library_ui/grid.rs#L270), [`ui/dr-ui/src/library_ui/grid.rs:559`](../../ui/dr-ui/src/library_ui/grid.rs#L559), [`ui/dr-ui/src/library_ui/grid.rs:683`](../../ui/dr-ui/src/library_ui/grid.rs#L683), [`ui/dr-ui/src/library_ui/open.rs:108`](../../ui/dr-ui/src/library_ui/open.rs#L108), [`ui/dr-ui/src/library_ui/open.rs:36`](../../ui/dr-ui/src/library_ui/open.rs#L36), [`ui/dr-ui/src/library_ui/open.rs:69`](../../ui/dr-ui/src/library_ui/open.rs#L69), [`ui/dr-ui/src/library_ui/open.rs:805`](../../ui/dr-ui/src/library_ui/open.rs#L805), [`ui/dr-ui/src/library_ui/open.rs:822`](../../ui/dr-ui/src/library_ui/open.rs#L822), [`ui/dr-ui/src/library_ui/open.rs:920`](../../ui/dr-ui/src/library_ui/open.rs#L920), [`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:171`](../../ui/dr-ui/ui/adjust.slint#L171), [`ui/dr-ui/ui/app.slint:2698`](../../ui/dr-ui/ui/app.slint#L2698), [`ui/dr-ui/ui/app.slint:2736`](../../ui/dr-ui/ui/app.slint#L2736) |
-| 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) |
+| 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:492`](../../core/dr-types/src/settings.rs#L492), [`ui/dr-ui/src/develop/rows.rs:118`](../../ui/dr-ui/src/develop/rows.rs#L118), [`ui/dr-ui/src/lib.rs:3221`](../../ui/dr-ui/src/lib.rs#L3221), [`ui/dr-ui/ui/adjust.slint:974`](../../ui/dr-ui/ui/adjust.slint#L974), [`ui/dr-ui/ui/app.slint:2017`](../../ui/dr-ui/ui/app.slint#L2017), [`ui/dr-ui/ui/settings.slint:681`](../../ui/dr-ui/ui/settings.slint#L681), [`ui/dr-ui/ui/toolrail.slint:89`](../../ui/dr-ui/ui/toolrail.slint#L89) |
+| FR-UI-8 | [`core/dr-catalog/src/collections.rs:654`](../../core/dr-catalog/src/collections.rs#L654), [`core/dr-catalog/src/collections.rs:675`](../../core/dr-catalog/src/collections.rs#L675), [`core/dr-types/src/place.rs:1`](../../core/dr-types/src/place.rs#L1), [`ui/dr-ui/src/derived_sync.rs:216`](../../ui/dr-ui/src/derived_sync.rs#L216), [`ui/dr-ui/src/derived_sync.rs:81`](../../ui/dr-ui/src/derived_sync.rs#L81), [`ui/dr-ui/src/derived_sync.rs:894`](../../ui/dr-ui/src/derived_sync.rs#L894), [`ui/dr-ui/src/derived_sync.rs:904`](../../ui/dr-ui/src/derived_sync.rs#L904), [`ui/dr-ui/src/derived_sync.rs:986`](../../ui/dr-ui/src/derived_sync.rs#L986), [`ui/dr-ui/src/library/cells.rs:274`](../../ui/dr-ui/src/library/cells.rs#L274), [`ui/dr-ui/src/library/cells.rs:553`](../../ui/dr-ui/src/library/cells.rs#L553), [`ui/dr-ui/src/library/cells.rs:619`](../../ui/dr-ui/src/library/cells.rs#L619), [`ui/dr-ui/src/library/paths.rs:22`](../../ui/dr-ui/src/library/paths.rs#L22), [`ui/dr-ui/src/library_ui/controller.rs:189`](../../ui/dr-ui/src/library_ui/controller.rs#L189), [`ui/dr-ui/src/library_ui/controller.rs:924`](../../ui/dr-ui/src/library_ui/controller.rs#L924), [`ui/dr-ui/src/library_ui/filter_bar.rs:671`](../../ui/dr-ui/src/library_ui/filter_bar.rs#L671), [`ui/dr-ui/src/library_ui/grid.rs:205`](../../ui/dr-ui/src/library_ui/grid.rs#L205), [`ui/dr-ui/src/library_ui/grid.rs:247`](../../ui/dr-ui/src/library_ui/grid.rs#L247), [`ui/dr-ui/src/library_ui/grid.rs:276`](../../ui/dr-ui/src/library_ui/grid.rs#L276), [`ui/dr-ui/src/library_ui/grid.rs:582`](../../ui/dr-ui/src/library_ui/grid.rs#L582), [`ui/dr-ui/src/library_ui/grid.rs:708`](../../ui/dr-ui/src/library_ui/grid.rs#L708), [`ui/dr-ui/src/library_ui/open.rs:118`](../../ui/dr-ui/src/library_ui/open.rs#L118), [`ui/dr-ui/src/library_ui/open.rs:36`](../../ui/dr-ui/src/library_ui/open.rs#L36), [`ui/dr-ui/src/library_ui/open.rs:71`](../../ui/dr-ui/src/library_ui/open.rs#L71), [`ui/dr-ui/src/library_ui/open.rs:827`](../../ui/dr-ui/src/library_ui/open.rs#L827), [`ui/dr-ui/src/library_ui/open.rs:844`](../../ui/dr-ui/src/library_ui/open.rs#L844), [`ui/dr-ui/src/library_ui/open.rs:942`](../../ui/dr-ui/src/library_ui/open.rs#L942), [`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:171`](../../ui/dr-ui/ui/adjust.slint#L171), [`ui/dr-ui/ui/app.slint:2433`](../../ui/dr-ui/ui/app.slint#L2433), [`ui/dr-ui/ui/app.slint:2471`](../../ui/dr-ui/ui/app.slint#L2471) |
+| 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:1031`](../../ui/dr-ui/ui/library.slint#L1031), [`ui/dr-ui/ui/library.slint:1179`](../../ui/dr-ui/ui/library.slint#L1179), [`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/repairs.rs:1`](../../ui/dr-ui/src/repairs.rs#L1) |
-| NFR-ARCH-3 | [`ui/dr-ui/src/develop_ui.rs:343`](../../ui/dr-ui/src/develop_ui.rs#L343), [`ui/dr-ui/src/export.rs:1822`](../../ui/dr-ui/src/export.rs#L1822), [`ui/dr-ui/src/export.rs:1849`](../../ui/dr-ui/src/export.rs#L1849), [`ui/dr-ui/src/export.rs:419`](../../ui/dr-ui/src/export.rs#L419), [`ui/dr-ui/src/export.rs:445`](../../ui/dr-ui/src/export.rs#L445), [`ui/dr-ui/ui/app.slint:1106`](../../ui/dr-ui/ui/app.slint#L1106), [`ui/dr-ui/ui/library.slint:4339`](../../ui/dr-ui/ui/library.slint#L4339) |
-| 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:521`](../../ui/dr-ui/src/export.rs#L521) |
+| NFR-ARCH-3 | [`ui/dr-ui/src/develop_ui.rs:348`](../../ui/dr-ui/src/develop_ui.rs#L348), [`ui/dr-ui/src/export.rs:1823`](../../ui/dr-ui/src/export.rs#L1823), [`ui/dr-ui/src/export.rs:1850`](../../ui/dr-ui/src/export.rs#L1850), [`ui/dr-ui/src/export.rs:420`](../../ui/dr-ui/src/export.rs#L420), [`ui/dr-ui/src/export.rs:446`](../../ui/dr-ui/src/export.rs#L446), [`ui/dr-ui/ui/library.slint:4609`](../../ui/dr-ui/ui/library.slint#L4609), [`ui/dr-ui/ui/library.slint:748`](../../ui/dr-ui/ui/library.slint#L748) |
+| 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:522`](../../ui/dr-ui/src/export.rs#L522) |
| NFR-COMPAT-1 | [`core/dr-gpu/src/lib.rs:286`](../../core/dr-gpu/src/lib.rs#L286) |
-| NFR-OPS-1 | [`core/dr-gpu/src/lib.rs:339`](../../core/dr-gpu/src/lib.rs#L339), [`platform/dr-plat/src/diagnostics.rs:1`](../../platform/dr-plat/src/diagnostics.rs#L1), [`platform/dr-plat/src/diagnostics/bundle.rs:1`](../../platform/dr-plat/src/diagnostics/bundle.rs#L1), [`platform/dr-plat/src/state.rs:1`](../../platform/dr-plat/src/state.rs#L1), [`ui/dr-ui/src/lib.rs:1462`](../../ui/dr-ui/src/lib.rs#L1462), [`ui/dr-ui/ui/app.slint:115`](../../ui/dr-ui/ui/app.slint#L115), [`ui/dr-ui/ui/app.slint:1429`](../../ui/dr-ui/ui/app.slint#L1429), [`ui/dr-ui/ui/settings.slint:1015`](../../ui/dr-ui/ui/settings.slint#L1015), [`ui/dr-ui/ui/settings.slint:154`](../../ui/dr-ui/ui/settings.slint#L154) |
+| NFR-OPS-1 | [`core/dr-gpu/src/lib.rs:339`](../../core/dr-gpu/src/lib.rs#L339), [`platform/dr-plat/src/diagnostics.rs:1`](../../platform/dr-plat/src/diagnostics.rs#L1), [`platform/dr-plat/src/diagnostics/bundle.rs:1`](../../platform/dr-plat/src/diagnostics/bundle.rs#L1), [`platform/dr-plat/src/state.rs:1`](../../platform/dr-plat/src/state.rs#L1), [`ui/dr-ui/src/lib.rs:1463`](../../ui/dr-ui/src/lib.rs#L1463), [`ui/dr-ui/ui/app.slint:1165`](../../ui/dr-ui/ui/app.slint#L1165), [`ui/dr-ui/ui/app.slint:116`](../../ui/dr-ui/ui/app.slint#L116), [`ui/dr-ui/ui/settings.slint:1015`](../../ui/dr-ui/ui/settings.slint#L1015), [`ui/dr-ui/ui/settings.slint:154`](../../ui/dr-ui/ui/settings.slint#L154) |
| 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/render.rs:348`](../../ui/dr-ui/src/develop/render.rs#L348), [`ui/dr-ui/src/lib.rs:2324`](../../ui/dr-ui/src/lib.rs#L2324) |
+| 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/render.rs:348`](../../ui/dr-ui/src/develop/render.rs#L348), [`ui/dr-ui/src/lib.rs:2325`](../../ui/dr-ui/src/lib.rs#L2325) |
| NFR-P3 | [`tools/bench/src/thumbnails.rs:1`](../../tools/bench/src/thumbnails.rs#L1) |
-| NFR-P5 | [`core/dr-catalog/src/schema.rs:564`](../../core/dr-catalog/src/schema.rs#L564), [`ui/dr-ui/src/library/cells.rs:382`](../../ui/dr-ui/src/library/cells.rs#L382), [`ui/dr-ui/src/library/cells.rs:708`](../../ui/dr-ui/src/library/cells.rs#L708), [`ui/dr-ui/src/library_ui/controller.rs:58`](../../ui/dr-ui/src/library_ui/controller.rs#L58), [`ui/dr-ui/src/library_ui/timeline.rs:365`](../../ui/dr-ui/src/library_ui/timeline.rs#L365) |
-| NFR-P9 | [`core/dr-catalog/src/schema.rs:917`](../../core/dr-catalog/src/schema.rs#L917), [`core/dr-face/src/references.rs:1`](../../core/dr-face/src/references.rs#L1), [`ui/dr-ui/src/collections_ui/mod.rs:1`](../../ui/dr-ui/src/collections_ui/mod.rs#L1), [`ui/dr-ui/src/export.rs:1005`](../../ui/dr-ui/src/export.rs#L1005), [`ui/dr-ui/src/library/mod.rs:1`](../../ui/dr-ui/src/library/mod.rs#L1), [`ui/dr-ui/src/library_ui/mod.rs:1`](../../ui/dr-ui/src/library_ui/mod.rs#L1), [`ui/dr-ui/src/trash.rs:1`](../../ui/dr-ui/src/trash.rs#L1) |
+| NFR-P5 | [`core/dr-catalog/src/schema.rs:564`](../../core/dr-catalog/src/schema.rs#L564), [`ui/dr-ui/src/library/cells.rs:382`](../../ui/dr-ui/src/library/cells.rs#L382), [`ui/dr-ui/src/library/cells.rs:708`](../../ui/dr-ui/src/library/cells.rs#L708), [`ui/dr-ui/src/library_ui/controller.rs:58`](../../ui/dr-ui/src/library_ui/controller.rs#L58), [`ui/dr-ui/src/library_ui/timeline.rs:382`](../../ui/dr-ui/src/library_ui/timeline.rs#L382) |
+| NFR-P9 | [`core/dr-catalog/src/schema.rs:917`](../../core/dr-catalog/src/schema.rs#L917), [`core/dr-face/src/references.rs:1`](../../core/dr-face/src/references.rs#L1), [`ui/dr-ui/src/collections_ui/mod.rs:1`](../../ui/dr-ui/src/collections_ui/mod.rs#L1), [`ui/dr-ui/src/export.rs:1006`](../../ui/dr-ui/src/export.rs#L1006), [`ui/dr-ui/src/library/mod.rs:1`](../../ui/dr-ui/src/library/mod.rs#L1), [`ui/dr-ui/src/library_ui/mod.rs:1`](../../ui/dr-ui/src/library_ui/mod.rs#L1), [`ui/dr-ui/src/trash.rs:1`](../../ui/dr-ui/src/trash.rs#L1) |
| NFR-PORT-1 | [`core/dr-catalog/src/walk.rs:1`](../../core/dr-catalog/src/walk.rs#L1), [`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/dirs.rs:1`](../../platform/dr-plat/src/dirs.rs#L1), [`platform/dr-plat/src/display.rs:1`](../../platform/dr-plat/src/display.rs#L1), [`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:287`](../../platform/dr-plat/src/storage.rs#L287), [`platform/dr-plat/src/storage.rs:344`](../../platform/dr-plat/src/storage.rs#L344), [`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) |
| NFR-PORT-2 | [`core/dr-gpu/src/lib.rs:1`](../../core/dr-gpu/src/lib.rs#L1) |
| NFR-PORT-3 | [`platform/dr-plat/src/storage.rs:1`](../../platform/dr-plat/src/storage.rs#L1) |
| NFR-R1 | [`core/dr-catalog/src/schema.rs:361`](../../core/dr-catalog/src/schema.rs#L361), [`core/dr-catalog/src/sync.rs:1`](../../core/dr-catalog/src/sync.rs#L1), [`core/dr-gpu/src/lib.rs:194`](../../core/dr-gpu/src/lib.rs#L194), [`core/dr-sync/src/account.rs:240`](../../core/dr-sync/src/account.rs#L240), [`ui/dr-ui/src/library/paths.rs:69`](../../ui/dr-ui/src/library/paths.rs#L69) |
-| NFR-R2 | [`core/dr-catalog/src/recovery.rs:1`](../../core/dr-catalog/src/recovery.rs#L1), [`core/dr-catalog/src/recovery.rs:222`](../../core/dr-catalog/src/recovery.rs#L222), [`core/dr-catalog/src/sync.rs:61`](../../core/dr-catalog/src/sync.rs#L61), [`core/dr-catalog/src/trash.rs:1`](../../core/dr-catalog/src/trash.rs#L1), [`ui/dr-ui/src/derived_sync.rs:613`](../../ui/dr-ui/src/derived_sync.rs#L613), [`ui/dr-ui/src/derived_sync.rs:736`](../../ui/dr-ui/src/derived_sync.rs#L736), [`ui/dr-ui/src/library_ui/sync.rs:22`](../../ui/dr-ui/src/library_ui/sync.rs#L22), [`ui/dr-ui/src/library_ui/sync.rs:340`](../../ui/dr-ui/src/library_ui/sync.rs#L340) |
+| NFR-R2 | [`core/dr-catalog/src/recovery.rs:1`](../../core/dr-catalog/src/recovery.rs#L1), [`core/dr-catalog/src/recovery.rs:222`](../../core/dr-catalog/src/recovery.rs#L222), [`core/dr-catalog/src/sync.rs:61`](../../core/dr-catalog/src/sync.rs#L61), [`core/dr-catalog/src/trash.rs:1`](../../core/dr-catalog/src/trash.rs#L1), [`ui/dr-ui/src/derived_sync.rs:613`](../../ui/dr-ui/src/derived_sync.rs#L613), [`ui/dr-ui/src/derived_sync.rs:736`](../../ui/dr-ui/src/derived_sync.rs#L736), [`ui/dr-ui/src/library_ui/sync.rs:22`](../../ui/dr-ui/src/library_ui/sync.rs#L22), [`ui/dr-ui/src/library_ui/sync.rs:345`](../../ui/dr-ui/src/library_ui/sync.rs#L345) |
| NFR-R3 | [`core/dr-decode/src/error.rs:30`](../../core/dr-decode/src/error.rs#L30) |
-| NFR-R4 | [`core/dr-types/src/settings.rs:92`](../../core/dr-types/src/settings.rs#L92), [`ui/dr-ui/src/library/xmp.rs:25`](../../ui/dr-ui/src/library/xmp.rs#L25), [`ui/dr-ui/src/library/xmp.rs:9`](../../ui/dr-ui/src/library/xmp.rs#L9), [`ui/dr-ui/src/library_ui/controller.rs:387`](../../ui/dr-ui/src/library_ui/controller.rs#L387), [`ui/dr-ui/src/library_ui/controller.rs:532`](../../ui/dr-ui/src/library_ui/controller.rs#L532), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:503`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L503), [`ui/dr-ui/src/settings_ui.rs:558`](../../ui/dr-ui/src/settings_ui.rs#L558), [`ui/dr-ui/src/xmp_sync.rs:1`](../../ui/dr-ui/src/xmp_sync.rs#L1), [`ui/dr-ui/ui/settings.slint:1093`](../../ui/dr-ui/ui/settings.slint#L1093), [`ui/dr-ui/ui/settings.slint:199`](../../ui/dr-ui/ui/settings.slint#L199) |
+| NFR-R4 | [`core/dr-types/src/settings.rs:92`](../../core/dr-types/src/settings.rs#L92), [`ui/dr-ui/src/library/xmp.rs:25`](../../ui/dr-ui/src/library/xmp.rs#L25), [`ui/dr-ui/src/library/xmp.rs:9`](../../ui/dr-ui/src/library/xmp.rs#L9), [`ui/dr-ui/src/library_ui/controller.rs:387`](../../ui/dr-ui/src/library_ui/controller.rs#L387), [`ui/dr-ui/src/library_ui/controller.rs:532`](../../ui/dr-ui/src/library_ui/controller.rs#L532), [`ui/dr-ui/src/library_ui/ratings_keywords.rs:529`](../../ui/dr-ui/src/library_ui/ratings_keywords.rs#L529), [`ui/dr-ui/src/settings_ui.rs:558`](../../ui/dr-ui/src/settings_ui.rs#L558), [`ui/dr-ui/src/xmp_sync.rs:1`](../../ui/dr-ui/src/xmp_sync.rs#L1), [`ui/dr-ui/ui/settings.slint:1093`](../../ui/dr-ui/ui/settings.slint#L1093), [`ui/dr-ui/ui/settings.slint:199`](../../ui/dr-ui/ui/settings.slint#L199) |
| NFR-R5 | [`core/dr-catalog/src/collections.rs:1`](../../core/dr-catalog/src/collections.rs#L1), [`core/dr-catalog/src/error.rs:1`](../../core/dr-catalog/src/error.rs#L1), [`core/dr-catalog/src/keywords.rs:1`](../../core/dr-catalog/src/keywords.rs#L1), [`core/dr-catalog/src/schema.rs:1`](../../core/dr-catalog/src/schema.rs#L1) |
| NFR-R6 | [`core/dr-catalog/src/error.rs:1`](../../core/dr-catalog/src/error.rs#L1), [`core/dr-catalog/src/lib.rs:255`](../../core/dr-catalog/src/lib.rs#L255), [`core/dr-catalog/src/recovery.rs:1`](../../core/dr-catalog/src/recovery.rs#L1) |
| NFR-R7 | [`core/dr-gpu/src/error.rs:1`](../../core/dr-gpu/src/error.rs#L1) |
| NFR-R8 | [`core/dr-gpu/src/error.rs:1`](../../core/dr-gpu/src/error.rs#L1) |
-| NFR-RES-1 | [`core/dr-gpu/src/adjust.rs:1057`](../../core/dr-gpu/src/adjust.rs#L1057), [`core/dr-pipeline/src/history.rs:86`](../../core/dr-pipeline/src/history.rs#L86), [`ui/dr-ui/src/develop/render.rs:519`](../../ui/dr-ui/src/develop/render.rs#L519), [`ui/dr-ui/src/identity_ui.rs:125`](../../ui/dr-ui/src/identity_ui.rs#L125), [`ui/dr-ui/src/lib.rs:101`](../../ui/dr-ui/src/lib.rs#L101), [`ui/dr-ui/src/memory.rs:1`](../../ui/dr-ui/src/memory.rs#L1) |
+| NFR-RES-1 | [`core/dr-gpu/src/adjust.rs:1057`](../../core/dr-gpu/src/adjust.rs#L1057), [`core/dr-pipeline/src/history.rs:86`](../../core/dr-pipeline/src/history.rs#L86), [`ui/dr-ui/src/develop/render.rs:519`](../../ui/dr-ui/src/develop/render.rs#L519), [`ui/dr-ui/src/identity_ui.rs:125`](../../ui/dr-ui/src/identity_ui.rs#L125), [`ui/dr-ui/src/lib.rs:102`](../../ui/dr-ui/src/lib.rs#L102), [`ui/dr-ui/src/memory.rs:1`](../../ui/dr-ui/src/memory.rs#L1) |
| NFR-RES-2 | [`ui/dr-ui/src/faces.rs:462`](../../ui/dr-ui/src/faces.rs#L462), [`ui/dr-ui/src/library/sweep.rs:241`](../../ui/dr-ui/src/library/sweep.rs#L241), [`ui/dr-ui/src/repairs.rs:1140`](../../ui/dr-ui/src/repairs.rs#L1140), [`ui/dr-ui/src/repairs.rs:1`](../../ui/dr-ui/src/repairs.rs#L1) |
| NFR-RES-4 | [`core/dr-catalog/src/cache.rs:1`](../../core/dr-catalog/src/cache.rs#L1), [`core/dr-catalog/src/face_shard.rs:1`](../../core/dr-catalog/src/face_shard.rs#L1), [`core/dr-catalog/src/schema.rs:1182`](../../core/dr-catalog/src/schema.rs#L1182), [`core/dr-gpu/src/lib.rs:95`](../../core/dr-gpu/src/lib.rs#L95), [`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), [`core/dr-thumbs/src/lib.rs:393`](../../core/dr-thumbs/src/lib.rs#L393) |
| NFR-SEC-1 | [`core/dr-decode/src/error.rs:1`](../../core/dr-decode/src/error.rs#L1), [`core/dr-decode/src/error.rs:30`](../../core/dr-decode/src/error.rs#L30) |
diff --git a/docs/gestures.md b/docs/gestures.md
index 77c66ee..fdcdaf9 100644
--- a/docs/gestures.md
+++ b/docs/gestures.md
@@ -25,7 +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:2026`
+`ui/dr-ui/ui/app.slint:1762`
### Move a magnified photograph about
@@ -34,7 +34,7 @@ Anchored on the fingers' midpoint, and on the pointer, so the gesture reads as m
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:2117`
+`ui/dr-ui/ui/app.slint:1853`
### Paint a mask by hand
@@ -43,7 +43,7 @@ Only once there is something outside the viewport to reach, which is why the cur
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:2204`
+`ui/dr-ui/ui/app.slint:1940`
### Take back the last change
@@ -53,7 +53,7 @@ A model's mask stops inside a shoulder and leaks into the hair, and no single ed
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:2425`
+`ui/dr-ui/ui/app.slint:2160`
### Do it again after taking it back
@@ -61,7 +61,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:2438`
+`ui/dr-ui/ui/app.slint:2173`
### Copy the settings from this photograph
@@ -71,7 +71,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:2471`
+`ui/dr-ui/ui/app.slint:2206`
### Paste the settings onto this photograph
@@ -81,7 +81,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:2483`
+`ui/dr-ui/ui/app.slint:2218`
### Change which group of adjustments is on screen
@@ -91,7 +91,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:2511`
+`ui/dr-ui/ui/app.slint:2246`
### Look at the photograph at 1:1
@@ -101,7 +101,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:2546`
+`ui/dr-ui/ui/app.slint:2281`
### Move to the next or previous photograph
@@ -111,7 +111,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:2598`
+`ui/dr-ui/ui/app.slint:2333`
### See the photograph before you edited it
@@ -121,7 +121,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:2722`
+`ui/dr-ui/ui/app.slint:2457`
### Put one control back to its default
@@ -264,7 +264,7 @@ The right match confidence is a property of your library, not of the model. "Wha
Touch has no ctrl, so without a mode there is no way to select a second photograph — the first tap would open it. The hold is the fast way in and the button is the one that can be found.
-`ui/dr-ui/ui/library.slint:1302`
+`ui/dr-ui/ui/library.slint:1572`
### Add or remove one photograph
@@ -273,7 +273,7 @@ Touch has no ctrl, so without a mode there is no way to select a second photogra
While selecting, a tap never opens. That is the whole point of the mode: one meaning per gesture at a time. Press Done to get tap-to-open back.
-`ui/dr-ui/ui/library.slint:1311`
+`ui/dr-ui/ui/library.slint:1581`
### Leave selecting
@@ -281,7 +281,7 @@ While selecting, a tap never opens. That is the whole point of the mode: one mea
- **Pointer** — Press Done in the header
- **Keyboard** — Escape
-`ui/dr-ui/ui/library.slint:1319`
+`ui/dr-ui/ui/library.slint:1589`
### Pick a photograph up to drag it
@@ -290,7 +290,7 @@ While selecting, a tap never opens. That is the whole point of the mode: one mea
A finger on a photograph might be starting a scroll, and for the first half-second the grid assumes it is. Holding says otherwise, and the ring is the grid saying it heard — from there the drag cannot be lost to a scroll. A mouse never waits: the cursor is precise enough that a sideways drag is unambiguous from the first pixel.
-`ui/dr-ui/ui/library.slint:1349`
+`ui/dr-ui/ui/library.slint:1619`
### Select a range
@@ -299,7 +299,7 @@ A finger on a photograph might be starting a scroll, and for the first half-seco
This replaced a double tap, which had no visible state and could take forty photographs by accident. The run is resolved by the catalog rather than by what is on screen, so the grid can scroll between the two taps — the ranges that hurt on a tablet are longer than a screenful, which is exactly where a finger sweep runs out.
-`ui/dr-ui/ui/library.slint:1414`
+`ui/dr-ui/ui/library.slint:1684`
### Take the blinks out of a burst
@@ -308,7 +308,7 @@ This replaced a double tap, which had no visible state and could take forty phot
Face indexing reads each face's eyes. The chip drops frames where the chosen people are caught blinking, and leaves sunglasses and eyes it could not read alone.
-`ui/dr-ui/ui/library.slint:2113`
+`ui/dr-ui/ui/library.slint:2383`
### Find photographs with two people in them
@@ -317,7 +317,7 @@ Face indexing reads each face's eyes. The chip drops frames where the chosen peo
"Any of them" is a union and "all of them" is an intersection. The tray is where both terms and the choice between them live, because a filter belongs on the filter bar.
-`ui/dr-ui/ui/library.slint:2142`
+`ui/dr-ui/ui/library.slint:2412`
### Resize the thumbnails
@@ -326,7 +326,7 @@ Face indexing reads each face's eyes. The chip drops frames where the chosen peo
There is no wheel on a tablet, so without the pinch the cell size could only be changed by a control a finger cannot reach.
-`ui/dr-ui/ui/library.slint:2802`
+`ui/dr-ui/ui/library.slint:3072`
### File photographs in a collection
@@ -335,7 +335,7 @@ There is no wheel on a tablet, so without the pinch the cell size could only be
The selection is what the drag carries, which is why selecting several is worth the mode: forty photographs file in one gesture.
-`ui/dr-ui/ui/library.slint:2999`
+`ui/dr-ui/ui/library.slint:3269`
### Open a photograph
@@ -344,7 +344,7 @@ The selection is what the drag carries, which is why selecting several is worth
A tap opens; a tap that *moved* does not. Travel is what separates a deliberate tap from a hand brushing past, and it is the only thing that does: the two are the same length. An earlier version required the finger to dwell 120 ms instead, and that rejected ordinary taps — a real tap is often quicker than a brush.
-`ui/dr-ui/ui/library.slint:3267`
+`ui/dr-ui/ui/library.slint:3537`
### Rate a photograph without opening it
@@ -354,7 +354,7 @@ A tap opens; a tap that *moved* does not. Travel is what separates a deliberate
A star has to take the press without it also reaching the cell, or every rating throws the user into develop.
-`ui/dr-ui/ui/library.slint:3387`
+`ui/dr-ui/ui/library.slint:3657`
### Choose the frame a folded burst shows
@@ -363,7 +363,7 @@ A star has to take the press without it also reaching the cell, or every rating
A folded burst draws its earliest frame, which is a fact about the clock and not a judgement about the photograph — nothing in this application ranks a frame (FR-CULL-5). But the point of a burst is that one of the twelve is better than the other eleven, and the photographer is the only one who knows which. So the choice is offered on the frames themselves, while they are open and side by side, which is the one moment the alternatives are on screen to be compared.
-`ui/dr-ui/ui/library.slint:3518`
+`ui/dr-ui/ui/library.slint:3788`
### Drop the selection but keep selecting
@@ -372,7 +372,7 @@ A folded burst draws its earliest frame, which is a fact about the clock and not
Distinct from Done, which leaves the mode entirely. Clearing keeps it, so the next selection can start straight away.
-`ui/dr-ui/ui/library.slint:4184`
+`ui/dr-ui/ui/library.slint:4454`
### Select everything the grid is showing
@@ -381,7 +381,7 @@ Distinct from Done, which leaves the mode entirely. Clearing keeps it, so the ne
A scoped grid of two hundred frames is two hundred taps otherwise, and "all of them, except those three" is a far more common shape than the taps it took to say it.
-`ui/dr-ui/ui/library.slint:4201`
+`ui/dr-ui/ui/library.slint:4471`
### Take photographs out of a collection
@@ -390,4 +390,4 @@ A scoped grid of two hundred frames is two hundred taps otherwise, and "all of t
The badge on a cell says a photograph is filed in three collections and never which. This is the sheet that names them, and the only way out of one the grid is not currently scoped to.
-`ui/dr-ui/ui/library.slint:4325`
+`ui/dr-ui/ui/library.slint:4595`
diff --git a/ui/dr-ui/src/bursts.rs b/ui/dr-ui/src/bursts.rs
index 358cf89..f063f5c 100644
--- a/ui/dr-ui/src/bursts.rs
+++ b/ui/dr-ui/src/bursts.rs
@@ -45,9 +45,9 @@ use dr_catalog::bursts::{self, Rules, Signature};
use dr_catalog::Catalog;
use dr_thumbs::{ThumbSize, ThumbStore};
use dr_types::ImageId;
-use slint::Model as _;
+use slint::{ComponentHandle as _, Model as _};
-use crate::AppWindow;
+use crate::{AppWindow, Library};
/// How many signatures are written per transaction.
///
@@ -364,7 +364,7 @@ pub fn sync_badges(window: &AppWindow, catalog: &Catalog, ids: &[ImageId]) {
}
};
- let model = window.get_library_cells();
+ let model = window.global::().get_library_cells();
for (row, id) in ids.iter().enumerate() {
let (count, expanded, representative) = match found.get(id) {
Some(m) => (m.size as i32, m.expanded, m.representative),
diff --git a/ui/dr-ui/src/collections_ui/drag.rs b/ui/dr-ui/src/collections_ui/drag.rs
index c17645c..696c0d4 100644
--- a/ui/dr-ui/src/collections_ui/drag.rs
+++ b/ui/dr-ui/src/collections_ui/drag.rs
@@ -10,7 +10,7 @@ use dr_catalog::Catalog;
use dr_types::CollectionId;
use slint::ComponentHandle;
-use crate::AppWindow;
+use crate::{AppWindow, Library};
use super::controller::CollectionsController;
use super::tree_sync::refresh_tree;
@@ -280,11 +280,11 @@ pub(super) fn arm_hold(window: &AppWindow, ctl: &Rc, row:
// This half happens whether or not selection mode was already on —
// it is the half a *drag* needs, and a drag out of a selection of
// forty starts in a mode that is already on.
- w.set_library_held_row(row);
+ w.global::().set_library_held_row(row);
if !ctl_cb.select_mode.get() {
ctl_cb.select_mode.set(true);
- w.set_library_select_mode(true);
+ w.global::().set_library_select_mode(true);
}
// The release that follows this hold must not also open the image:
diff --git a/ui/dr-ui/src/collections_ui/press.rs b/ui/dr-ui/src/collections_ui/press.rs
index 528f568..866281b 100644
--- a/ui/dr-ui/src/collections_ui/press.rs
+++ b/ui/dr-ui/src/collections_ui/press.rs
@@ -6,8 +6,9 @@ use std::collections::BTreeSet;
use std::rc::Rc;
use dr_types::ImageId;
+use slint::ComponentHandle as _;
-use crate::AppWindow;
+use crate::{AppWindow, Library};
use super::controller::CollectionsController;
use super::tree_sync::sync_selection;
@@ -292,7 +293,7 @@ pub fn cancel_press(window: &AppWindow, ctl: &Rc, ids: &[
// has to put it back down, or the ring stays open around a cell nobody is
// touching and the grid stays frozen with it.
ctl.pending_toggle.set(None);
- window.set_library_held_row(-1);
+ window.global::().set_library_held_row(-1);
let Some(undo) = ctl.press_undo.borrow_mut().take() else {
return;
diff --git a/ui/dr-ui/src/collections_ui/trash.rs b/ui/dr-ui/src/collections_ui/trash.rs
index 8eb7b34..5152890 100644
--- a/ui/dr-ui/src/collections_ui/trash.rs
+++ b/ui/dr-ui/src/collections_ui/trash.rs
@@ -12,7 +12,7 @@ use dr_catalog::Catalog;
use dr_types::ImageId;
use slint::ComponentHandle;
-use crate::{AppWindow, Collections};
+use crate::{AppWindow, Collections, Library};
use super::controller::CollectionsController;
use super::tree_sync::refresh_tree;
@@ -56,7 +56,9 @@ pub(super) fn start_trash(
}
log::info!("moving {} image(s) to the trash", moves.len());
- window.set_library_status(format!("Moving {} to the trash…", moves.len()).into());
+ window
+ .global::()
+ .set_library_status(format!("Moving {} to the trash…", moves.len()).into());
// The images are leaving the grid; a selection pointing at them would
// survive as a set of ids the user can no longer see.
ctl.clear_selection();
@@ -131,7 +133,9 @@ pub(super) fn start_restore(
}
log::info!("restoring {} image(s) from the trash", moves.len());
- window.set_library_status(format!("Restoring {}…", moves.len()).into());
+ window
+ .global::()
+ .set_library_status(format!("Restoring {}…", moves.len()).into());
// The images are leaving the trash view, so a selection pointing at them
// would survive as ids the user can no longer see.
ctl.clear_selection();
@@ -214,7 +218,7 @@ pub(super) fn drain_trash(
if failed > 0 {
job.detail(format!("{failed} failed"));
}
- w.set_library_status(status.into());
+ w.global::().set_library_status(status.into());
}
TrashMessage::Done { moved, failed } => {
// Reported honestly, including the partial case: "38 of
@@ -233,7 +237,7 @@ pub(super) fn drain_trash(
} else {
job.fail(status.clone());
}
- w.set_library_status(status.into());
+ w.global::().set_library_status(status.into());
if let Some(first) = failed.first() {
w.global::()
.set_collection_error(first.as_str().into());
diff --git a/ui/dr-ui/src/collections_ui/tree_sync.rs b/ui/dr-ui/src/collections_ui/tree_sync.rs
index 6c48aef..e37f769 100644
--- a/ui/dr-ui/src/collections_ui/tree_sync.rs
+++ b/ui/dr-ui/src/collections_ui/tree_sync.rs
@@ -13,7 +13,7 @@ use dr_catalog::Catalog;
use dr_types::{CollectionId, ImageId};
use slint::{ComponentHandle as _, Model as _};
-use crate::{AppWindow, CollectionRow, Collections};
+use crate::{AppWindow, CollectionRow, Collections, Library};
use super::controller::CollectionsController;
@@ -195,7 +195,7 @@ fn offline_state(
/// Separate from [`sync_selection`] because the two differ: the selection
/// persists after the drag, the lift lasts only while it is in flight.
pub fn sync_lifted(window: &AppWindow, lifted: &[ImageId], ids: &[ImageId]) {
- let model = window.get_library_cells();
+ let model = window.global::().get_library_cells();
for (row, id) in ids.iter().enumerate() {
let want = lifted.contains(id);
if let Some(mut cell) = model.row_data(row) {
@@ -213,7 +213,7 @@ pub fn sync_lifted(window: &AppWindow, lifted: &[ImageId], ids: &[ImageId]) {
/// this is what keeps the two in step after a scrub, a drop, or a click.
pub fn sync_selection(window: &AppWindow, ctl: &Rc, ids: &[ImageId]) {
let selection = ctl.selection.borrow();
- let model = window.get_library_cells();
+ let model = window.global::().get_library_cells();
// The anchor is deliberately **not** pushed to the grid.
//
@@ -238,7 +238,9 @@ pub fn sync_selection(window: &AppWindow, ctl: &Rc, ids:
}
}
- window.set_library_selected_count(selection.len() as i32);
+ window
+ .global::()
+ .set_library_selected_count(selection.len() as i32);
}
/// TRACES: FR-CAT-7
@@ -261,7 +263,7 @@ pub(super) fn sync_reorderable(window: &AppWindow) {
.filter_map(|i| rows.row_data(i))
.find(|r| r.id == id)
.is_some_and(|r| !r.smart && !r.has_children);
- window.set_library_reorderable(manual);
+ window.global::().set_library_reorderable(manual);
}
/// Refresh the per-cell "in this many collections" badges.
@@ -300,7 +302,7 @@ pub fn sync_badges(window: &AppWindow, catalog: &Catalog, ids: &[ImageId]) {
}
}
- let model = window.get_library_cells();
+ let model = window.global::().get_library_cells();
for (row, id) in ids.iter().enumerate() {
let want = counts.get(&(id.0 as i64)).copied().unwrap_or(0);
if let Some(mut cell) = model.row_data(row) {
diff --git a/ui/dr-ui/src/collections_ui/wiring_grid.rs b/ui/dr-ui/src/collections_ui/wiring_grid.rs
index 3b4775f..38be30e 100644
--- a/ui/dr-ui/src/collections_ui/wiring_grid.rs
+++ b/ui/dr-ui/src/collections_ui/wiring_grid.rs
@@ -16,7 +16,7 @@ use dr_types::{CollectionId, ImageId};
use slint::{ComponentHandle, Model as _};
use crate::library;
-use crate::{AppWindow, Collections};
+use crate::{AppWindow, Collections, Library};
use super::controller::{decide_drop, CollectionsController, Drop};
use super::drag::{
@@ -102,35 +102,37 @@ fn wire_selection(
let weak = window.as_weak();
let ctl = ctl.clone();
let visible = visible_ids.clone();
- window.on_library_cell_pressed(move |row, ctrl_held, shift_held| {
- let Some(w) = weak.upgrade() else { return };
- let ids = visible();
+ window
+ .global::()
+ .on_library_cell_pressed(move |row, ctrl_held, shift_held| {
+ let Some(w) = weak.upgrade() else { return };
+ let ids = visible();
- // Consulted by the click that follows: a modified press is building
- // a selection and must not also navigate to develop.
- ctl.modified_press.set(ctrl_held || shift_held);
+ // Consulted by the click that follows: a modified press is building
+ // a selection and must not also navigate to develop.
+ ctl.modified_press.set(ctrl_held || shift_held);
- // Where the window starts, so the press is recorded as the ordinal
- // it is rather than as a row that stops meaning this photograph on
- // the next scroll.
- let offset = w.get_library_offset().max(0) as usize;
- select_row(&w, &ctl, &ids, offset, row as usize, ctrl_held, shift_held);
+ // Where the window starts, so the press is recorded as the ordinal
+ // it is rather than as a row that stops meaning this photograph on
+ // the next scroll.
+ let offset = w.global::().get_library_offset().max(0) as usize;
+ select_row(&w, &ctl, &ids, offset, row as usize, ctrl_held, shift_held);
- // TRACES: FR-UI-2 | FR-UI-4 | FR-CAT-7
- // And start counting, in case this press is a hold. The press has
- // already selected this one cell; what the hold adds is the *mode*,
- // so the taps that follow go on selecting instead of opening the
- // next photograph the user touches — and the *pick-up*, which is
- // what makes the drag reliable.
- //
- // Armed even when the mode is already on, which it did not used to
- // be: there was nothing left for the hold to switch on, so it was
- // skipped. But the mode being on is exactly the state a
- // multi-image drag starts from, and skipping the hold left that
- // drag with no pick-up and no cue — the one gesture that most
- // needed both. See `arm_hold`.
- arm_hold(&w, &ctl, row);
- });
+ // TRACES: FR-UI-2 | FR-UI-4 | FR-CAT-7
+ // And start counting, in case this press is a hold. The press has
+ // already selected this one cell; what the hold adds is the *mode*,
+ // so the taps that follow go on selecting instead of opening the
+ // next photograph the user touches — and the *pick-up*, which is
+ // what makes the drag reliable.
+ //
+ // Armed even when the mode is already on, which it did not used to
+ // be: there was nothing left for the hold to switch on, so it was
+ // skipped. But the mode being on is exactly the state a
+ // multi-image drag starts from, and skipping the hold left that
+ // drag with no pick-up and no cue — the one gesture that most
+ // needed both. See `arm_hold`.
+ arm_hold(&w, &ctl, row);
+ });
}
// TRACES: FR-UI-2 | FR-UI-4
@@ -138,9 +140,11 @@ fn wire_selection(
// travelled. Either way the hold is off.
{
let ctl = ctl.clone();
- window.on_library_cell_press_ended(move || {
- *ctl.hold_timer.borrow_mut() = None;
- });
+ window
+ .global::()
+ .on_library_cell_press_ended(move || {
+ *ctl.hold_timer.borrow_mut() = None;
+ });
}
// TRACES: FR-CAT-5
@@ -155,11 +159,13 @@ fn wire_selection(
let weak = window.as_weak();
let ctl = ctl.clone();
let visible = visible_ids.clone();
- window.on_library_clear_selection(move || {
- let Some(w) = weak.upgrade() else { return };
- ctl.clear_selection();
- sync_selection(&w, &ctl, &visible());
- });
+ window
+ .global::()
+ .on_library_clear_selection(move || {
+ let Some(w) = weak.upgrade() else { return };
+ ctl.clear_selection();
+ sync_selection(&w, &ctl, &visible());
+ });
}
// TRACES: FR-CAT-7
@@ -182,75 +188,77 @@ fn wire_selection(
let catalog = catalog.clone();
let visible = visible_ids.clone();
let reload = on_scope_changed.clone();
- window.on_library_reorder_to(move |row, after| {
- let Some(w) = weak.upgrade() else { return };
- // Both guards belong here rather than only in `library.slint`: the
- // scope can change between the drag starting and the drop landing.
- if !w.get_library_reorderable() {
- return;
- }
- let Some(scope) = *ctl.scope.borrow() else {
- return;
- };
-
- let moving = ctl.selected();
- if moving.is_empty() {
- return;
- }
-
- let ids = visible();
- let Some(&target) = usize::try_from(row).ok().and_then(|r| ids.get(r)) else {
- return;
- };
-
- // Dropped on one of its own. There is no gap between a run and
- // itself to land in, and rewriting the whole membership to say so
- // would be a revision bump for no change.
- if moving.contains(&target) {
- return;
- }
-
- let borrow = catalog.borrow();
- let Some(cat) = borrow.as_ref() else { return };
-
- let current = match library::read_member_order(cat, scope) {
- Ok(current) => current,
- Err(e) => {
- w.global::().set_collection_error(
- format!("reading the collection's order: {e}").into(),
- );
+ window
+ .global::()
+ .on_library_reorder_to(move |row, after| {
+ let Some(w) = weak.upgrade() else { return };
+ // Both guards belong here rather than only in `library.slint`: the
+ // scope can change between the drag starting and the drop landing.
+ if !w.global::().get_library_reorderable() {
return;
}
- };
- let wanted = library::reordered(¤t, &moving, target, after);
+ let Some(scope) = *ctl.scope.borrow() else {
+ return;
+ };
- match coll::set_order(cat.connection(), scope, &wanted) {
- Ok(()) => {
- w.global::()
- .set_collection_error(slint::SharedString::new());
- w.set_library_status(
- format!(
- "{} photograph{} moved",
- moving.len(),
- if moving.len() == 1 { "" } else { "s" }
- )
- .into(),
- );
- drop(borrow);
+ let moving = ctl.selected();
+ if moving.is_empty() {
+ return;
+ }
- // The selection survives. It is what was just moved, and
- // dropping it would make a second nudge — which is how a
- // drag-to-reorder is usually corrected — start over.
- reload();
- sync_selection(&w, &ctl, &visible());
+ let ids = visible();
+ let Some(&target) = usize::try_from(row).ok().and_then(|r| ids.get(r)) else {
+ return;
+ };
+
+ // Dropped on one of its own. There is no gap between a run and
+ // itself to land in, and rewriting the whole membership to say so
+ // would be a revision bump for no change.
+ if moving.contains(&target) {
+ return;
}
- Err(e) => {
- drop(borrow);
- w.global::()
- .set_collection_error(format!("reordering: {e}").into());
+
+ let borrow = catalog.borrow();
+ let Some(cat) = borrow.as_ref() else { return };
+
+ let current = match library::read_member_order(cat, scope) {
+ Ok(current) => current,
+ Err(e) => {
+ w.global::().set_collection_error(
+ format!("reading the collection's order: {e}").into(),
+ );
+ return;
+ }
+ };
+ let wanted = library::reordered(¤t, &moving, target, after);
+
+ match coll::set_order(cat.connection(), scope, &wanted) {
+ Ok(()) => {
+ w.global::()
+ .set_collection_error(slint::SharedString::new());
+ w.global::().set_library_status(
+ format!(
+ "{} photograph{} moved",
+ moving.len(),
+ if moving.len() == 1 { "" } else { "s" }
+ )
+ .into(),
+ );
+ drop(borrow);
+
+ // The selection survives. It is what was just moved, and
+ // dropping it would make a second nudge — which is how a
+ // drag-to-reorder is usually corrected — start over.
+ reload();
+ sync_selection(&w, &ctl, &visible());
+ }
+ Err(e) => {
+ drop(borrow);
+ w.global::()
+ .set_collection_error(format!("reordering: {e}").into());
+ }
}
- }
- });
+ });
}
// TRACES: FR-CAT-5 | FR-UI-4
@@ -270,10 +278,10 @@ fn wire_selection(
let weak = window.as_weak();
let ctl = ctl.clone();
let visible = visible_ids.clone();
- window.on_library_select_all(move || {
+ window.global::().on_library_select_all(move || {
let Some(w) = weak.upgrade() else { return };
let ids = visible();
- let total = w.get_library_total().max(0) as usize;
+ let total = w.global::().get_library_total().max(0) as usize;
if total == 0 {
return;
}
@@ -337,69 +345,71 @@ fn wire_selection_filing(
let catalog = catalog.clone();
let visible = visible_ids.clone();
let reload = on_scope_changed.clone();
- window.on_library_collection_from_selection(move |name| {
- let Some(w) = weak.upgrade() else { return };
- let images = ctl.selected();
- if images.is_empty() {
- return;
- }
-
- let borrow = catalog.borrow();
- let Some(cat) = borrow.as_ref() else {
- w.global::()
- .set_collection_error("Open a library first.".into());
- return;
- };
-
- // The sheet refuses an empty name in two places, so this is
- // belt-and-braces rather than a path the UI can reach — but a
- // collection with no name at all is unfindable in the tree, and
- // falling back to the placeholder is recoverable where an empty
- // row is not.
- let name = match name.trim() {
- "" => unique_name(cat.connection(), None),
- typed => typed.to_string(),
- };
-
- // The id is not carried out. It used to be, to open the rename
- // field on the row it names; now the name is already right, and
- // `refresh_tree` redraws the tree from the catalog either way.
- let made = coll::create(cat.connection(), &name, None, CollectionKind::Manual)
- .and_then(|id| coll::add_images(cat.connection(), id, &images));
-
- match made {
- Ok(added) => {
- w.global::()
- .set_collection_error(slint::SharedString::new());
- w.set_library_status(
- format!(
- "{added} photograph{} in {name}",
- if added == 1 { "" } else { "s" }
- )
- .into(),
- );
- refresh_tree(&w, &ctl, cat);
- drop(borrow);
-
- // The selection has been filed; holding on to it invites
- // the next press acting on photographs the user considers
- // dealt with.
- ctl.clear_selection();
- sync_selection(&w, &ctl, &visible());
-
- // No rename opened here. The name was chosen before the
- // collection existed, so there is nothing left to correct —
- // and opening the sidebar's field is what stranded the
- // keyboard on a tablet.
- reload();
+ window
+ .global::()
+ .on_library_collection_from_selection(move |name| {
+ let Some(w) = weak.upgrade() else { return };
+ let images = ctl.selected();
+ if images.is_empty() {
+ return;
}
- Err(e) => {
- drop(borrow);
+
+ let borrow = catalog.borrow();
+ let Some(cat) = borrow.as_ref() else {
w.global::()
- .set_collection_error(format!("making a collection: {e}").into());
+ .set_collection_error("Open a library first.".into());
+ return;
+ };
+
+ // The sheet refuses an empty name in two places, so this is
+ // belt-and-braces rather than a path the UI can reach — but a
+ // collection with no name at all is unfindable in the tree, and
+ // falling back to the placeholder is recoverable where an empty
+ // row is not.
+ let name = match name.trim() {
+ "" => unique_name(cat.connection(), None),
+ typed => typed.to_string(),
+ };
+
+ // The id is not carried out. It used to be, to open the rename
+ // field on the row it names; now the name is already right, and
+ // `refresh_tree` redraws the tree from the catalog either way.
+ let made = coll::create(cat.connection(), &name, None, CollectionKind::Manual)
+ .and_then(|id| coll::add_images(cat.connection(), id, &images));
+
+ match made {
+ Ok(added) => {
+ w.global::()
+ .set_collection_error(slint::SharedString::new());
+ w.global::().set_library_status(
+ format!(
+ "{added} photograph{} in {name}",
+ if added == 1 { "" } else { "s" }
+ )
+ .into(),
+ );
+ refresh_tree(&w, &ctl, cat);
+ drop(borrow);
+
+ // The selection has been filed; holding on to it invites
+ // the next press acting on photographs the user considers
+ // dealt with.
+ ctl.clear_selection();
+ sync_selection(&w, &ctl, &visible());
+
+ // No rename opened here. The name was chosen before the
+ // collection existed, so there is nothing left to correct —
+ // and opening the sidebar's field is what stranded the
+ // keyboard on a tablet.
+ reload();
+ }
+ Err(e) => {
+ drop(borrow);
+ w.global::()
+ .set_collection_error(format!("making a collection: {e}").into());
+ }
}
- }
- });
+ });
}
// TRACES: FR-UI-2 | FR-UI-4
@@ -410,23 +420,25 @@ fn wire_selection_filing(
let weak = window.as_weak();
let ctl = ctl.clone();
let visible = visible_ids.clone();
- window.on_library_toggle_select_mode(move || {
- let Some(w) = weak.upgrade() else { return };
- let on = !ctl.select_mode.get();
- ctl.select_mode.set(on);
- w.set_library_select_mode(on);
- *ctl.hold_timer.borrow_mut() = None;
+ window
+ .global::()
+ .on_library_toggle_select_mode(move || {
+ let Some(w) = weak.upgrade() else { return };
+ let on = !ctl.select_mode.get();
+ ctl.select_mode.set(on);
+ w.global::().set_library_select_mode(on);
+ *ctl.hold_timer.borrow_mut() = None;
- // Leaving the mode drops the selection. "Done" reads as finishing
- // with these photographs, and a selection that outlived the mode
- // would still be acted on by the buttons in the header — which is
- // how forty images get exported by a user who thought they had put
- // them down.
- if !on {
- ctl.clear_selection();
- sync_selection(&w, &ctl, &visible());
- }
- });
+ // Leaving the mode drops the selection. "Done" reads as finishing
+ // with these photographs, and a selection that outlived the mode
+ // would still be acted on by the buttons in the header — which is
+ // how forty images get exported by a user who thought they had put
+ // them down.
+ if !on {
+ ctl.clear_selection();
+ sync_selection(&w, &ctl, &visible());
+ }
+ });
}
// TRACES: FR-CAT-7 | FR-UI-4
@@ -437,59 +449,61 @@ fn wire_selection_filing(
let catalog = catalog.clone();
let visible = visible_ids.clone();
let reload = on_scope_changed.clone();
- window.on_library_file_in_collection(move |id, moves| {
- let Some(w) = weak.upgrade() else { return };
- let target = CollectionId(id as u64);
- let chosen = ctl.selected();
- if chosen.is_empty() {
- return;
- }
-
- let borrow = catalog.borrow();
- let Some(cat) = borrow.as_ref() else { return };
-
- // Moving is only a move when there is somewhere to move *from*.
- // Unscoped, the sheet does not offer it; this guards the callback
- // anyway, and degrades to filing rather than refusing.
- let from = if moves { *ctl.scope.borrow() } else { None };
- let result = match from {
- Some(from) => coll::move_images(cat.connection(), from, target, &chosen),
- None => coll::add_images(cat.connection(), target, &chosen),
- };
-
- match result {
- Ok(filed) => {
- w.global::()
- .set_collection_error(slint::SharedString::new());
- // The honest count, as the drop reports it: claiming all
- // twelve when nine were already there teaches the user to
- // distrust every number the app shows them.
- let msg = if from.is_some() {
- format!("Moved {filed} of {}", chosen.len())
- } else if filed == chosen.len() {
- format!("Added {filed} to collection")
- } else {
- format!(
- "Added {filed} of {} — the rest were already there",
- chosen.len()
- )
- };
- w.set_library_status(msg.into());
-
- refresh_tree(&w, &ctl, cat);
- sync_badges(&w, cat, &visible());
- // A move changes what the collection on screen holds, so
- // the grid has to be reread; filing elsewhere does not, but
- // the badge count on every cell just changed and the reread
- // is one query.
- drop(borrow);
- reload();
+ window
+ .global::()
+ .on_library_file_in_collection(move |id, moves| {
+ let Some(w) = weak.upgrade() else { return };
+ let target = CollectionId(id as u64);
+ let chosen = ctl.selected();
+ if chosen.is_empty() {
+ return;
}
- Err(e) => w
- .global::()
- .set_collection_error(format!("filing: {e}").into()),
- }
- });
+
+ let borrow = catalog.borrow();
+ let Some(cat) = borrow.as_ref() else { return };
+
+ // Moving is only a move when there is somewhere to move *from*.
+ // Unscoped, the sheet does not offer it; this guards the callback
+ // anyway, and degrades to filing rather than refusing.
+ let from = if moves { *ctl.scope.borrow() } else { None };
+ let result = match from {
+ Some(from) => coll::move_images(cat.connection(), from, target, &chosen),
+ None => coll::add_images(cat.connection(), target, &chosen),
+ };
+
+ match result {
+ Ok(filed) => {
+ w.global::()
+ .set_collection_error(slint::SharedString::new());
+ // The honest count, as the drop reports it: claiming all
+ // twelve when nine were already there teaches the user to
+ // distrust every number the app shows them.
+ let msg = if from.is_some() {
+ format!("Moved {filed} of {}", chosen.len())
+ } else if filed == chosen.len() {
+ format!("Added {filed} to collection")
+ } else {
+ format!(
+ "Added {filed} of {} — the rest were already there",
+ chosen.len()
+ )
+ };
+ w.global::().set_library_status(msg.into());
+
+ refresh_tree(&w, &ctl, cat);
+ sync_badges(&w, cat, &visible());
+ // A move changes what the collection on screen holds, so
+ // the grid has to be reread; filing elsewhere does not, but
+ // the badge count on every cell just changed and the reread
+ // is one query.
+ drop(borrow);
+ reload();
+ }
+ Err(e) => w
+ .global::()
+ .set_collection_error(format!("filing: {e}").into()),
+ }
+ });
}
}
@@ -529,7 +543,7 @@ fn wire_drag(
// nothing outside the application can interpret it as a paste.
{
let ctl = ctl.clone();
- window.on_library_drag_payload(move || {
+ window.global::().on_library_drag_payload(move || {
let carried = ctl.dragging.borrow().clone();
let mut data = slint::DataTransfer::default();
data.set_user_data(Rc::new(carried));
@@ -554,67 +568,70 @@ fn wire_drag(
let weak = window.as_weak();
let ctl = ctl.clone();
let visible = visible_ids.clone();
- window.on_library_drag_started(move |row| {
- let Some(w) = weak.upgrade() else { return };
- let ids = visible();
+ window
+ .global::()
+ .on_library_drag_started(move |row| {
+ let Some(w) = weak.upgrade() else { return };
+ let ids = visible();
- // TRACES: FR-UI-4
- // A drag is not a hold, and the timer must not outlive the press
- // that armed it. Grabbing a cell and moving inside 450 ms left the
- // hold armed underneath the drag, so it fired mid-gesture and put
- // the grid into selection mode the user had not asked for — the
- // drag finished into a mode that changed what every later tap
- // meant. The pinch already cancels for exactly this reason.
- *ctl.hold_timer.borrow_mut() = None;
+ // TRACES: FR-UI-4
+ // A drag is not a hold, and the timer must not outlive the press
+ // that armed it. Grabbing a cell and moving inside 450 ms left the
+ // hold armed underneath the drag, so it fired mid-gesture and put
+ // the grid into selection mode the user had not asked for — the
+ // drag finished into a mode that changed what every later tap
+ // meant. The pinch already cancels for exactly this reason.
+ *ctl.hold_timer.borrow_mut() = None;
- // TRACES: FR-CAT-7
- // And this press was not a tap, so it never gets to take anything
- // out of the selection — see [`Press::Deferred`]. Dropped here as
- // well as on the next press because the drag reads the selection
- // one line below, and a removal still pending would be a
- // photograph the user can see is selected and the drop would not
- // carry.
- ctl.pending_toggle.set(None);
+ // TRACES: FR-CAT-7
+ // And this press was not a tap, so it never gets to take anything
+ // out of the selection — see [`Press::Deferred`]. Dropped here as
+ // well as on the next press because the drag reads the selection
+ // one line below, and a removal still pending would be a
+ // photograph the user can see is selected and the drop would not
+ // carry.
+ ctl.pending_toggle.set(None);
- // Dragging an *unselected* cell carries only that one, and makes it
- // the selection — otherwise the images that travel are not the ones
- // the user grabbed. Dragging a selected cell carries the whole
- // selection, which is the multi-image gesture.
- let carried: Vec = {
- let mut selection = ctl.selection.borrow_mut();
- match ids.get(row as usize) {
- Some(id) if !selection.contains(id) => {
- selection.clear();
- selection.insert(*id);
- vec![*id]
+ // Dragging an *unselected* cell carries only that one, and makes it
+ // the selection — otherwise the images that travel are not the ones
+ // the user grabbed. Dragging a selected cell carries the whole
+ // selection, which is the multi-image gesture.
+ let carried: Vec = {
+ let mut selection = ctl.selection.borrow_mut();
+ match ids.get(row as usize) {
+ Some(id) if !selection.contains(id) => {
+ selection.clear();
+ selection.insert(*id);
+ vec![*id]
+ }
+ _ => selection.iter().copied().collect(),
}
- _ => selection.iter().copied().collect(),
- }
- };
+ };
- // The bitmap under the cursor, built from the thumbnails already in
- // the model — the drag carries what the user can see, and a cell
- // whose preview has not landed yet contributes nothing rather than
- // a placeholder.
- let thumbs: Vec = {
- let model = w.get_library_cells();
- carried
- .iter()
- .filter_map(|id| ids.iter().position(|v| v == id))
- .filter_map(|row| model.row_data(row))
- .filter(|c| c.has_thumb)
- .map(|c| c.thumbnail)
- .collect()
- };
- w.set_library_drag_image(drag_image_via_file(compose_drag_image(&thumbs)));
+ // The bitmap under the cursor, built from the thumbnails already in
+ // the model — the drag carries what the user can see, and a cell
+ // whose preview has not landed yet contributes nothing rather than
+ // a placeholder.
+ let thumbs: Vec = {
+ let model = w.global::().get_library_cells();
+ carried
+ .iter()
+ .filter_map(|id| ids.iter().position(|v| v == id))
+ .filter_map(|row| model.row_data(row))
+ .filter(|c| c.has_thumb)
+ .map(|c| c.thumbnail)
+ .collect()
+ };
+ w.global::()
+ .set_library_drag_image(drag_image_via_file(compose_drag_image(&thumbs)));
- *ctl.dragging.borrow_mut() = carried.clone();
- sync_selection(&w, &ctl, &ids);
- // The lift-out: these cells fade and shrink in place, so the grid
- // shows where the photographs came from while the cursor shows them
- // in full colour.
- sync_lifted(&w, &carried, &ids);
- });
+ *ctl.dragging.borrow_mut() = carried.clone();
+ sync_selection(&w, &ctl, &ids);
+ // The lift-out: these cells fade and shrink in place, so the grid
+ // shows where the photographs came from while the cursor shows them
+ // in full colour.
+ sync_lifted(&w, &carried, &ids);
+ });
}
// A drag dwelling over a collapsed collection springs it open, so a nested
@@ -676,7 +693,8 @@ fn wire_drag(
Ok(()) => {
w.global::()
.set_collection_error(slint::SharedString::new());
- w.set_library_status("Moved collection".into());
+ w.global::()
+ .set_library_status("Moved collection".into());
let borrow = catalog.borrow();
if let Some(cat) = borrow.as_ref() {
refresh_tree(&w, &ctl, cat);
@@ -717,7 +735,7 @@ fn wire_drag(
carried.len()
)
};
- w.set_library_status(msg.into());
+ w.global::().set_library_status(msg.into());
}
Err(e) => w
.global::()
@@ -743,53 +761,56 @@ fn wire_drag(
let visible = visible_ids.clone();
let reload = on_scope_changed.clone();
let session = session.clone();
- window.on_library_drag_finished(move || {
- let Some(w) = weak.upgrade() else { return };
+ window
+ .global::()
+ .on_library_drag_finished(move || {
+ let Some(w) = weak.upgrade() else { return };
- let landed = ctl.dropped_on.borrow_mut().take();
- let to_trash = ctl.trash_requested.borrow_mut().take();
- ctl.dragging.borrow_mut().clear();
- // The grid clears this itself on the cancel that starts a drag;
- // this is for the endings that reach no cell — a drop, or a drag
- // abandoned over nothing.
- w.set_library_held_row(-1);
- *ctl.hover_id.borrow_mut() = None;
- *ctl.spring_timer.borrow_mut() = None;
+ let landed = ctl.dropped_on.borrow_mut().take();
+ let to_trash = ctl.trash_requested.borrow_mut().take();
+ ctl.dragging.borrow_mut().clear();
+ // The grid clears this itself on the cancel that starts a drag;
+ // this is for the endings that reach no cell — a drop, or a drag
+ // abandoned over nothing.
+ w.global::().set_library_held_row(-1);
+ *ctl.hover_id.borrow_mut() = None;
+ *ctl.spring_timer.borrow_mut() = None;
- // A soft delete, deferred out of the drop handler so the models it
- // replaces are no longer being walked.
- if let Some(images) = to_trash {
- start_trash(&w, &ctl, &catalog, &session, &images, &reload);
- }
-
- // The cells settle back into the grid, and the cursor bitmap is
- // released — it holds a copy of every thumbnail it composited.
- sync_lifted(&w, &[], &visible());
- w.set_library_drag_image(slint::Image::default());
- forget_drag_image_file();
-
- if landed.is_some() {
- let borrow = catalog.borrow();
- if let Some(cat) = borrow.as_ref() {
- // Counts changed on the target and every ancestor, and the
- // dropped images now carry one more collection badge.
- refresh_tree(&w, &ctl, cat);
- sync_badges(&w, cat, &visible());
+ // A soft delete, deferred out of the drop handler so the models it
+ // replaces are no longer being walked.
+ if let Some(images) = to_trash {
+ start_trash(&w, &ctl, &catalog, &session, &images, &reload);
}
- }
- // Put back whatever the spring opened on the way. The collection
- // that received the images — and its ancestors — stay open, since
- // that is where the user is now working; on an abandoned drag
- // `landed` is `None` and everything closes.
- collapse_spring_opened(&w, &ctl, &catalog, landed);
+ // The cells settle back into the grid, and the cursor bitmap is
+ // released — it holds a copy of every thumbnail it composited.
+ sync_lifted(&w, &[], &visible());
+ w.global::()
+ .set_library_drag_image(slint::Image::default());
+ forget_drag_image_file();
- // A drop into the collection currently being shown changes what that
- // collection holds, so the grid has to be reread.
- if landed.is_some() && landed == *ctl.scope.borrow() {
- reload();
- }
- });
+ if landed.is_some() {
+ let borrow = catalog.borrow();
+ if let Some(cat) = borrow.as_ref() {
+ // Counts changed on the target and every ancestor, and the
+ // dropped images now carry one more collection badge.
+ refresh_tree(&w, &ctl, cat);
+ sync_badges(&w, cat, &visible());
+ }
+ }
+
+ // Put back whatever the spring opened on the way. The collection
+ // that received the images — and its ancestors — stay open, since
+ // that is where the user is now working; on an abandoned drag
+ // `landed` is `None` and everything closes.
+ collapse_spring_opened(&w, &ctl, &catalog, landed);
+
+ // A drop into the collection currently being shown changes what that
+ // collection holds, so the grid has to be reread.
+ if landed.is_some() && landed == *ctl.scope.borrow() {
+ reload();
+ }
+ });
}
}
@@ -875,17 +896,19 @@ fn wire_trash_from_grid(
let session = session.clone();
let reload = on_scope_changed.clone();
let visible = visible_ids.clone();
- window.on_library_cell_trashed(move |row| {
- let Some(w) = weak.upgrade() else { return };
- // Resolved through the visible ids rather than the row index alone:
- // the grid is a window over the catalog, so a stale index from
- // before a scroll would name a different photograph — and here that
- // would move the wrong file.
- let Some(&id) = visible().get(row as usize) else {
- return;
- };
- start_trash(&w, &ctl, &catalog, &session, &[id], &reload);
- });
+ window
+ .global::()
+ .on_library_cell_trashed(move |row| {
+ let Some(w) = weak.upgrade() else { return };
+ // Resolved through the visible ids rather than the row index alone:
+ // the grid is a window over the catalog, so a stale index from
+ // before a scroll would name a different photograph — and here that
+ // would move the wrong file.
+ let Some(&id) = visible().get(row as usize) else {
+ return;
+ };
+ start_trash(&w, &ctl, &catalog, &session, &[id], &reload);
+ });
}
// `Delete` on the selection — the bulk gesture.
@@ -895,17 +918,20 @@ fn wire_trash_from_grid(
let catalog = catalog.clone();
let session = session.clone();
let reload = on_scope_changed.clone();
- window.on_library_trash_selection(move || {
- let Some(w) = weak.upgrade() else { return };
- let chosen = ctl.selected();
- if chosen.is_empty() {
- // A keystroke that does nothing reads as a broken key, so it
- // says why rather than failing silently.
- w.set_library_status("Select an image first".into());
- return;
- }
- start_trash(&w, &ctl, &catalog, &session, &chosen, &reload);
- });
+ window
+ .global::()
+ .on_library_trash_selection(move || {
+ let Some(w) = weak.upgrade() else { return };
+ let chosen = ctl.selected();
+ if chosen.is_empty() {
+ // A keystroke that does nothing reads as a broken key, so it
+ // says why rather than failing silently.
+ w.global::()
+ .set_library_status("Select an image first".into());
+ return;
+ }
+ start_trash(&w, &ctl, &catalog, &session, &chosen, &reload);
+ });
}
{
@@ -947,7 +973,8 @@ fn wire_trash_from_grid(
let ids: Vec = listed.iter().map(|t| t.image_id).collect();
log::info!("emptying trash: {} image(s)", ids.len());
- w.set_library_status(format!("Deleting {} image(s)…", ids.len()).into());
+ w.global::()
+ .set_library_status(format!("Deleting {} image(s)…", ids.len()).into());
let count = ids.len();
let rx = crate::trash::spawn_purge(
diff --git a/ui/dr-ui/src/collections_ui/wiring_tree.rs b/ui/dr-ui/src/collections_ui/wiring_tree.rs
index eac0c9f..053fd5c 100644
--- a/ui/dr-ui/src/collections_ui/wiring_tree.rs
+++ b/ui/dr-ui/src/collections_ui/wiring_tree.rs
@@ -13,7 +13,7 @@ use dr_catalog::Catalog;
use dr_types::{CollectionId, ImageId};
use slint::{ComponentHandle, Model as _};
-use crate::{AppWindow, Collections};
+use crate::{AppWindow, Collections, Library};
use super::controller::{
decide_delete, decide_release, CollectionsController, DeleteStep, Release,
@@ -236,41 +236,44 @@ pub(super) fn wire_remove(
let catalog = catalog.clone();
let visible = visible_ids.clone();
let reload = on_scope_changed.clone();
- window.on_library_remove_from_collection(move || {
- let Some(w) = weak.upgrade() else { return };
- let Some(scope) = *ctl.scope.borrow() else {
- // Unscoped, there is no collection to remove from. The button
- // is hidden in that state; this guards the callback anyway.
- return;
- };
- let chosen = ctl.selected();
- if chosen.is_empty() {
- return;
- }
-
- let borrow = catalog.borrow();
- let Some(cat) = borrow.as_ref() else { return };
-
- match coll::remove_images(cat.connection(), scope, &chosen) {
- Ok(n) => {
- w.global::()
- .set_collection_error(slint::SharedString::new());
- // Named explicitly as a membership change: the images are
- // still in the library, and a user who reads this as a
- // delete will not trust the feature again.
- w.set_library_status(
- format!("Removed {n} from this collection; still in the library").into(),
- );
- ctl.clear_selection();
- refresh_tree(&w, &ctl, cat);
- sync_badges(&w, cat, &visible());
- reload();
+ window
+ .global::()
+ .on_library_remove_from_collection(move || {
+ let Some(w) = weak.upgrade() else { return };
+ let Some(scope) = *ctl.scope.borrow() else {
+ // Unscoped, there is no collection to remove from. The button
+ // is hidden in that state; this guards the callback anyway.
+ return;
+ };
+ let chosen = ctl.selected();
+ if chosen.is_empty() {
+ return;
}
- Err(e) => w
- .global::()
- .set_collection_error(format!("removing: {e}").into()),
- }
- });
+
+ let borrow = catalog.borrow();
+ let Some(cat) = borrow.as_ref() else { return };
+
+ match coll::remove_images(cat.connection(), scope, &chosen) {
+ Ok(n) => {
+ w.global::()
+ .set_collection_error(slint::SharedString::new());
+ // Named explicitly as a membership change: the images are
+ // still in the library, and a user who reads this as a
+ // delete will not trust the feature again.
+ w.global::().set_library_status(
+ format!("Removed {n} from this collection; still in the library")
+ .into(),
+ );
+ ctl.clear_selection();
+ refresh_tree(&w, &ctl, cat);
+ sync_badges(&w, cat, &visible());
+ reload();
+ }
+ Err(e) => w
+ .global::()
+ .set_collection_error(format!("removing: {e}").into()),
+ }
+ });
}
}
@@ -421,7 +424,8 @@ pub(super) fn wire_row_drag(
Ok(()) => {
w.global::()
.set_collection_error(slint::SharedString::new());
- w.set_library_status("Moved to the top level".into());
+ w.global::()
+ .set_library_status("Moved to the top level".into());
refresh_tree(&w, &ctl, cat);
log::info!("promoted collection {} by drag", source.0);
}
@@ -537,7 +541,8 @@ pub(super) fn wire_row_menu(
Ok(()) => {
w.global::()
.set_collection_error(slint::SharedString::new());
- w.set_library_status("Moved to the top level".into());
+ w.global::()
+ .set_library_status("Moved to the top level".into());
close_row_menu(&w, &ctl);
refresh_tree(&w, &ctl, cat);
log::info!("promoted collection {} to the top level", id.0);
@@ -626,7 +631,7 @@ pub(super) fn wire_row_menu(
// Named as a membership change, as the removal button is:
// a user who reads this as a delete of their photographs
// will not trust the feature again.
- w.set_library_status(if holds > 0 {
+ w.global::().set_library_status(if holds > 0 {
format!(
"Deleted the collection; its {holds} photograph(s) stay in the library"
)
@@ -688,13 +693,15 @@ pub(super) fn wire_membership(
let weak = window.as_weak();
let ctl = ctl.clone();
let catalog = catalog.clone();
- window.on_library_open_membership(move || {
- let Some(w) = weak.upgrade() else { return };
- let borrow = catalog.borrow();
- let Some(cat) = borrow.as_ref() else { return };
- refresh_membership(&w, &ctl, cat);
- w.global::().set_membership_open(true);
- });
+ window
+ .global::()
+ .on_library_open_membership(move || {
+ let Some(w) = weak.upgrade() else { return };
+ let borrow = catalog.borrow();
+ let Some(cat) = borrow.as_ref() else { return };
+ refresh_membership(&w, &ctl, cat);
+ w.global::().set_membership_open(true);
+ });
}
{
@@ -724,7 +731,7 @@ pub(super) fn wire_membership(
.set_collection_error(slint::SharedString::new());
// The same wording the scoped button uses, and for the same
// reason: this is a membership change, not a delete.
- w.set_library_status(
+ w.global::().set_library_status(
format!("Removed {n} from that collection; still in the library")
.into(),
);
diff --git a/ui/dr-ui/src/develop_ui.rs b/ui/dr-ui/src/develop_ui.rs
index 97b7c71..18f5530 100644
--- a/ui/dr-ui/src/develop_ui.rs
+++ b/ui/dr-ui/src/develop_ui.rs
@@ -31,8 +31,8 @@ use crate::spots_ui;
use crate::{
apply_crop_aspect, batch_request, drain_outbox, export, groups_in_rail, refresh_export_label,
render_open_frame, sync_crop_aspect, sync_film, sync_framing, sync_rows, Adjustments,
- AppWindow, Develop, DevelopSession, Framing, Inspection, ParamRow, Peaking, Render, Steps,
- ViewMode,
+ AppWindow, Develop, DevelopSession, Framing, Inspection, Library, ParamRow, Peaking, Render,
+ Steps, ViewMode,
};
/// Shared state the develop screen's callbacks capture.
@@ -285,7 +285,7 @@ fn wire_export(window: &AppWindow, w: &DevelopWiring) {
// buttons share a worker slot, so starting a second run would
// drop the first's drain — leaving a batch still writing files
// with no progress row and a button that never comes back.
- if w.get_export_busy() || w.get_library_exporting() {
+ if w.get_export_busy() || w.global::().get_library_exporting() {
w.set_export_status("An export is already running".into());
return;
}
@@ -316,42 +316,50 @@ fn wire_export(window: &AppWindow, w: &DevelopWiring) {
let library = library.clone();
let collections = collections.clone();
let start = start.clone();
- window.on_library_export_selection(move || {
- let Some(w) = weak.upgrade() else { return };
- // See the develop button above for why one run excludes the
- // other. The button is a cancel by then, so this only catches
- // a batch started from develop and left running.
- if w.get_library_exporting() || w.get_export_busy() {
- w.set_library_status("An export is already running".into());
- return;
- }
+ window
+ .global::()
+ .on_library_export_selection(move || {
+ let Some(w) = weak.upgrade() else { return };
+ // See the develop button above for why one run excludes the
+ // other. The button is a cancel by then, so this only catches
+ // a batch started from develop and left running.
+ if w.global::().get_library_exporting() || w.get_export_busy() {
+ w.global::()
+ .set_library_status("An export is already running".into());
+ return;
+ }
- let sources = library.export_sources(&collections.selected());
- if sources.is_empty() {
- // Said out loud rather than ignored, matching what a paste
- // or a judgement keystroke does with an empty selection.
- w.set_library_status("Select an image first".into());
- return;
- }
+ let sources = library.export_sources(&collections.selected());
+ if sources.is_empty() {
+ // Said out loud rather than ignored, matching what a paste
+ // or a judgement keystroke does with an empty selection.
+ w.global::()
+ .set_library_status("Select an image first".into());
+ return;
+ }
- w.set_library_exporting(true);
- w.set_library_status(format!("Exporting {} images…", sources.len()).into());
- start(&w, sources, export::Reporting::Library);
- });
+ w.global::().set_library_exporting(true);
+ w.global::()
+ .set_library_status(format!("Exporting {} images…", sources.len()).into());
+ start(&w, sources, export::Reporting::Library);
+ });
}
// TRACES: NFR-ARCH-3
{
let weak = window.as_weak();
- window.on_library_cancel_export(move || {
- cancel.borrow().cancel();
- if let Some(w) = weak.upgrade() {
- // The worker stops at the next point it is safe to — which
- // may be a frame away — so the button says "asked for" and
- // not "done". The drain writes the real answer.
- w.set_library_status("Cancelling the export…".into());
- }
- });
+ window
+ .global::()
+ .on_library_cancel_export(move || {
+ cancel.borrow().cancel();
+ if let Some(w) = weak.upgrade() {
+ // The worker stops at the next point it is safe to — which
+ // may be a frame away — so the button says "asked for" and
+ // not "done". The drain writes the real answer.
+ w.global::()
+ .set_library_status("Cancelling the export…".into());
+ }
+ });
}
}
diff --git a/ui/dr-ui/src/export.rs b/ui/dr-ui/src/export.rs
index 37c27ae..0d6dd1f 100644
--- a/ui/dr-ui/src/export.rs
+++ b/ui/dr-ui/src/export.rs
@@ -67,8 +67,9 @@ use dr_export::{Encoded, NameContext};
use dr_sync::RemotePath;
use dr_sync::{Account, Connection};
use dr_types::{ExportSettings, ExportTarget};
+use slint::ComponentHandle as _;
-use crate::AppWindow;
+use crate::{AppWindow, Library};
/// Where exports wait for a server that is not there yet.
///
@@ -1131,7 +1132,7 @@ fn summarise(
fn report(window: &AppWindow, reporting: Reporting, text: &str) {
match reporting {
Reporting::Develop => window.set_export_status(text.into()),
- Reporting::Library => window.set_library_status(text.into()),
+ Reporting::Library => window.global::().set_library_status(text.into()),
}
}
@@ -1140,7 +1141,7 @@ fn settle(window: &AppWindow, reporting: Reporting, text: &str) {
report(window, reporting, text);
match reporting {
Reporting::Develop => window.set_export_busy(false),
- Reporting::Library => window.set_library_exporting(false),
+ Reporting::Library => window.global::().set_library_exporting(false),
}
}
diff --git a/ui/dr-ui/src/lib.rs b/ui/dr-ui/src/lib.rs
index 887ff1c..3dada8f 100644
--- a/ui/dr-ui/src/lib.rs
+++ b/ui/dr-ui/src/lib.rs
@@ -72,6 +72,7 @@ use std::rc::Rc;
use anyhow::Result;
use dr_decode::{Metadata, PreviewSize};
+use slint::ComponentHandle as _;
pub use develop::DevelopSession;
@@ -1841,7 +1842,7 @@ fn wire_import_and_merge(
// on the next sync pass, then look for it, exactly as an
// import does.
drain_outbox(&library_for_done);
- w.invoke_library_rescan();
+ w.global::().invoke_library_rescan();
},
);
}
@@ -1878,7 +1879,7 @@ fn wire_import_and_merge(
// the second is what the grid shows, so this asks for the scan
// that finds them rather than inserting rows itself.
if let Some(w) = weak.upgrade() {
- w.invoke_library_rescan();
+ w.global::().invoke_library_rescan();
}
},
);
@@ -3436,7 +3437,7 @@ fn back_one_step(w: &AppWindow) -> bool {
// 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
// back at all.
- has_grid: w.get_library_total() > 0,
+ has_grid: w.global::().get_library_total() > 0,
scoped: w.get_collection_selected() != 0,
};
diff --git a/ui/dr-ui/src/library_ui/filter_bar.rs b/ui/dr-ui/src/library_ui/filter_bar.rs
index dfd02b2..36bb1e6 100644
--- a/ui/dr-ui/src/library_ui/filter_bar.rs
+++ b/ui/dr-ui/src/library_ui/filter_bar.rs
@@ -12,7 +12,7 @@ use std::rc::Rc;
use slint::ComponentHandle;
use crate::library;
-use crate::{AppWindow, PersonChip, View};
+use crate::{AppWindow, Library, PersonChip, View};
use super::controller::LibraryController;
use super::offline::{
@@ -31,42 +31,48 @@ pub(super) fn wire_filter_ratings_and_people(window: &AppWindow, ctl: &Rc 0 {
- ctl.filter.borrow_mut().unjudged = false;
- }
- w.set_library_filter_min_rating(n.clamp(0, 5));
- w.set_library_filter_unjudged(ctl.filter.borrow().unjudged);
- refilter(&w, &ctl);
- });
+ window
+ .global::()
+ .on_library_filter_min_rating_changed(move |n| {
+ let Some(w) = weak.upgrade() else { return };
+ ctl.filter.borrow_mut().min_rating = n.clamp(0, 5) as u8;
+ // Stars and "unrated" are contradictory terms — asking for four
+ // stars *and* nothing judged matches nothing at all, which reads
+ // as a broken filter rather than an impossible question.
+ if n > 0 {
+ ctl.filter.borrow_mut().unjudged = false;
+ }
+ w.global::()
+ .set_library_filter_min_rating(n.clamp(0, 5));
+ w.global::()
+ .set_library_filter_unjudged(ctl.filter.borrow().unjudged);
+ refilter(&w, &ctl);
+ });
}
{
let weak = window.as_weak();
let ctl = ctl.clone();
- window.on_library_filter_unjudged_changed(move |on| {
- let Some(w) = weak.upgrade() else { return };
- {
- let mut f = ctl.filter.borrow_mut();
- f.unjudged = on;
- // See above: the two cannot both hold.
- if on {
- f.min_rating = 0;
- f.flag = None;
+ window
+ .global::()
+ .on_library_filter_unjudged_changed(move |on| {
+ let Some(w) = weak.upgrade() else { return };
+ {
+ let mut f = ctl.filter.borrow_mut();
+ f.unjudged = on;
+ // See above: the two cannot both hold.
+ if on {
+ f.min_rating = 0;
+ f.flag = None;
+ }
}
- }
- w.set_library_filter_unjudged(on);
- if on {
- w.set_library_filter_min_rating(0);
- w.set_library_filter_flag(0);
- }
- refilter(&w, &ctl);
- });
+ w.global::().set_library_filter_unjudged(on);
+ if on {
+ w.global::().set_library_filter_min_rating(0);
+ w.global::().set_library_filter_flag(0);
+ }
+ refilter(&w, &ctl);
+ });
}
{
@@ -101,99 +107,112 @@ pub(super) fn wire_filter_ratings_and_people(window: &AppWindow, ctl: &Rc()
+ .on_library_filter_person_cleared(move |id| {
+ let Some(w) = weak.upgrade() else { return };
+ ctl.filter
+ .borrow_mut()
+ .people
+ .retain(|p| *p != id.max(0) as u64);
+ drop_eyes_open_without_people(&w, &ctl);
+ push_people_chips(&w, &ctl);
+ refilter(&w, &ctl);
+ });
}
{
let weak = window.as_weak();
let ctl = ctl.clone();
- window.on_library_people_listed(move || {
- let Some(w) = weak.upgrade() else { return };
- push_people_roster(&w, &ctl);
- });
+ window
+ .global::()
+ .on_library_people_listed(move || {
+ let Some(w) = weak.upgrade() else { return };
+ push_people_roster(&w, &ctl);
+ });
}
{
let weak = window.as_weak();
let ctl = ctl.clone();
- window.on_library_filter_person_toggled(move |id| {
- let Some(w) = weak.upgrade() else { return };
- let person = id.max(0) as u64;
- {
- let mut f = ctl.filter.borrow_mut();
- if let Some(at) = f.people.iter().position(|p| *p == person) {
- f.people.remove(at);
- } else {
- f.people.push(person);
+ window
+ .global::()
+ .on_library_filter_person_toggled(move |id| {
+ let Some(w) = weak.upgrade() else { return };
+ let person = id.max(0) as u64;
+ {
+ let mut f = ctl.filter.borrow_mut();
+ if let Some(at) = f.people.iter().position(|p| *p == person) {
+ f.people.remove(at);
+ } else {
+ f.people.push(person);
+ }
}
- }
- drop_eyes_open_without_people(&w, &ctl);
- push_people_chips(&w, &ctl);
- refilter(&w, &ctl);
- });
+ drop_eyes_open_without_people(&w, &ctl);
+ push_people_chips(&w, &ctl);
+ refilter(&w, &ctl);
+ });
}
{
let weak = window.as_weak();
let ctl = ctl.clone();
- window.on_library_filter_eyes_open_toggled(move || {
- let Some(w) = weak.upgrade() else { return };
- let on = {
- let mut f = ctl.filter.borrow_mut();
- f.eyes_open = !f.eyes_open;
- f.eyes_open
- };
- w.set_library_filter_eyes_open(on);
- refilter(&w, &ctl);
- });
- }
-
- {
- let weak = window.as_weak();
- let ctl = ctl.clone();
- window.on_library_filter_people_mode_toggled(move || {
- let Some(w) = weak.upgrade() else { return };
- {
- let mut f = ctl.filter.borrow_mut();
- f.people_mode = match f.people_mode {
- library::PeopleMode::Any => library::PeopleMode::All,
- library::PeopleMode::All => library::PeopleMode::Any,
+ window
+ .global::()
+ .on_library_filter_eyes_open_toggled(move || {
+ let Some(w) = weak.upgrade() else { return };
+ let on = {
+ let mut f = ctl.filter.borrow_mut();
+ f.eyes_open = !f.eyes_open;
+ f.eyes_open
};
- }
- push_people_chips(&w, &ctl);
- refilter(&w, &ctl);
- });
+ w.global::().set_library_filter_eyes_open(on);
+ refilter(&w, &ctl);
+ });
}
{
let weak = window.as_weak();
let ctl = ctl.clone();
- window.on_library_filter_flag_changed(move |f| {
- let Some(w) = weak.upgrade() else { return };
- {
- let mut filter = ctl.filter.borrow_mut();
- filter.flag = match f {
- 1 => Some(dr_types::FlagState::Pick),
- 2 => Some(dr_types::FlagState::Reject),
- _ => None,
- };
- if f > 0 {
- filter.unjudged = false;
+ window
+ .global::()
+ .on_library_filter_people_mode_toggled(move || {
+ let Some(w) = weak.upgrade() else { return };
+ {
+ let mut f = ctl.filter.borrow_mut();
+ f.people_mode = match f.people_mode {
+ library::PeopleMode::Any => library::PeopleMode::All,
+ library::PeopleMode::All => library::PeopleMode::Any,
+ };
}
- }
- w.set_library_filter_flag(f);
- w.set_library_filter_unjudged(ctl.filter.borrow().unjudged);
- refilter(&w, &ctl);
- });
+ push_people_chips(&w, &ctl);
+ refilter(&w, &ctl);
+ });
+ }
+
+ {
+ let weak = window.as_weak();
+ let ctl = ctl.clone();
+ window
+ .global::()
+ .on_library_filter_flag_changed(move |f| {
+ let Some(w) = weak.upgrade() else { return };
+ {
+ let mut filter = ctl.filter.borrow_mut();
+ filter.flag = match f {
+ 1 => Some(dr_types::FlagState::Pick),
+ 2 => Some(dr_types::FlagState::Reject),
+ _ => None,
+ };
+ if f > 0 {
+ filter.unjudged = false;
+ }
+ }
+ w.global::().set_library_filter_flag(f);
+ w.global::()
+ .set_library_filter_unjudged(ctl.filter.borrow().unjudged);
+ refilter(&w, &ctl);
+ });
}
}
@@ -218,57 +237,59 @@ pub(super) fn wire_filter_dates(window: &AppWindow, ctl: &Rc)
{
let weak = window.as_weak();
let ctl = ctl.clone();
- window.on_library_toggle_date_range(move || {
- let Some(w) = weak.upgrade() else { return };
- // Whether the *controls* are showing, which is not the same as
- // whether a range is set — and reading it from the filter was why
- // pressing this did nothing. The fields are how a range gets set,
- // so requiring one before they appear is a door locked from the
- // inside.
- let on = !w.get_library_range_active();
- if on {
- // Seeded from the span the axis is drawn over, which is what
- // the user is looking at when they ask for "this range".
- //
- // Only a seed. If there is no catalog yet, or nothing in it
- // carries a capture date — dates are read from EXIF as
- // thumbnails load, so a freshly opened library has none — the
- // fields simply open empty and wait to be typed into. This
- // used to `return` in both cases, which meant the button
- // silently did nothing on exactly the libraries where a person
- // is most likely to be looking for a date.
- let seeded = {
- let borrow = ctl.catalog.borrow();
- borrow
- .as_ref()
- .and_then(|catalog| catalog_span(catalog, &ctl))
- .map(|span| {
- zoomed_span(
- span,
- *ctl.timeline_zoom.borrow(),
- *ctl.timeline_centre.borrow(),
- )
- })
- };
- if let Some(span) = seeded {
- // Through the same days-inclusive conversion a drag uses,
- // so a seeded range and a dragged one are the same kind of
- // thing — and so `show_range` reads this one back out as
- // the two days it covers.
- let (from, to) = dragged_range(span, 0.0, 1.0);
+ window
+ .global::()
+ .on_library_toggle_date_range(move || {
+ let Some(w) = weak.upgrade() else { return };
+ // Whether the *controls* are showing, which is not the same as
+ // whether a range is set — and reading it from the filter was why
+ // pressing this did nothing. The fields are how a range gets set,
+ // so requiring one before they appear is a door locked from the
+ // inside.
+ let on = !w.global::().get_library_range_active();
+ if on {
+ // Seeded from the span the axis is drawn over, which is what
+ // the user is looking at when they ask for "this range".
+ //
+ // Only a seed. If there is no catalog yet, or nothing in it
+ // carries a capture date — dates are read from EXIF as
+ // thumbnails load, so a freshly opened library has none — the
+ // fields simply open empty and wait to be typed into. This
+ // used to `return` in both cases, which meant the button
+ // silently did nothing on exactly the libraries where a person
+ // is most likely to be looking for a date.
+ let seeded = {
+ let borrow = ctl.catalog.borrow();
+ borrow
+ .as_ref()
+ .and_then(|catalog| catalog_span(catalog, &ctl))
+ .map(|span| {
+ zoomed_span(
+ span,
+ *ctl.timeline_zoom.borrow(),
+ *ctl.timeline_centre.borrow(),
+ )
+ })
+ };
+ if let Some(span) = seeded {
+ // Through the same days-inclusive conversion a drag uses,
+ // so a seeded range and a dragged one are the same kind of
+ // thing — and so `show_range` reads this one back out as
+ // the two days it covers.
+ let (from, to) = dragged_range(span, 0.0, 1.0);
+ let mut f = ctl.filter.borrow_mut();
+ f.captured_from = Some(from);
+ f.captured_to = Some(to);
+ }
+ } else {
let mut f = ctl.filter.borrow_mut();
- f.captured_from = Some(from);
- f.captured_to = Some(to);
+ f.captured_from = None;
+ f.captured_to = None;
}
- } else {
- let mut f = ctl.filter.borrow_mut();
- f.captured_from = None;
- f.captured_to = None;
- }
- w.set_library_range_active(on);
- show_range(&w, &ctl);
- refilter(&w, &ctl);
- });
+ w.global::().set_library_range_active(on);
+ show_range(&w, &ctl);
+ refilter(&w, &ctl);
+ });
}
// TRACES: FR-CAT-6 | FR-UI-2
@@ -289,39 +310,41 @@ pub(super) fn wire_filter_dates(window: &AppWindow, ctl: &Rc)
{
let weak = window.as_weak();
let ctl = ctl.clone();
- window.on_library_timeline_range_changed(move |a, b| {
- let Some(w) = weak.upgrade() else { return };
- let borrow = ctl.catalog.borrow();
- let Some(catalog) = borrow.as_ref() else {
- return;
- };
- let Some(full) = catalog_span(catalog, &ctl) else {
- return;
- };
- let span = zoomed_span(
- full,
- *ctl.timeline_zoom.borrow(),
- *ctl.timeline_centre.borrow(),
- );
- drop(borrow);
+ window
+ .global::()
+ .on_library_timeline_range_changed(move |a, b| {
+ let Some(w) = weak.upgrade() else { return };
+ let borrow = ctl.catalog.borrow();
+ let Some(catalog) = borrow.as_ref() else {
+ return;
+ };
+ let Some(full) = catalog_span(catalog, &ctl) else {
+ return;
+ };
+ let span = zoomed_span(
+ full,
+ *ctl.timeline_zoom.borrow(),
+ *ctl.timeline_centre.borrow(),
+ );
+ drop(borrow);
- let (from, to) = dragged_range(span, a, b);
- {
- let mut f = ctl.filter.borrow_mut();
- f.captured_from = Some(from);
- f.captured_to = Some(to);
- }
+ let (from, to) = dragged_range(span, a, b);
+ {
+ let mut f = ctl.filter.borrow_mut();
+ f.captured_from = Some(from);
+ f.captured_to = Some(to);
+ }
- // A dragged range cannot be mistyped, so any standing complaint
- // about the fields is now about a range that no longer exists.
- w.set_library_range_invalid(false);
- w.set_library_range_active(true);
- show_range(&w, &ctl);
- // Reloads the window, and `load_window` redraws the timeline —
- // which is what puts the band back under the finger that dropped
- // it, at the whole days it was snapped to.
- refilter(&w, &ctl);
- });
+ // A dragged range cannot be mistyped, so any standing complaint
+ // about the fields is now about a range that no longer exists.
+ w.global::().set_library_range_invalid(false);
+ w.global::().set_library_range_active(true);
+ show_range(&w, &ctl);
+ // Reloads the window, and `load_window` redraws the timeline —
+ // which is what puts the band back under the finger that dropped
+ // it, at the whole days it was snapped to.
+ refilter(&w, &ctl);
+ });
}
// TRACES: FR-CAT-6
@@ -334,39 +357,41 @@ pub(super) fn wire_filter_dates(window: &AppWindow, ctl: &Rc)
{
let weak = window.as_weak();
let ctl = ctl.clone();
- window.on_library_range_edited(move |from, to| {
- let Some(w) = weak.upgrade() else { return };
+ window
+ .global::()
+ .on_library_range_edited(move |from, to| {
+ let Some(w) = weak.upgrade() else { return };
- // Both ends, or neither. A range with one end parsed and the other
- // silently dropped is a filter nobody asked for, and the grid
- // going empty is a poor way to find out a date was mistyped.
- let (Some(from), Some(to)) = (
- dr_types::parse_date(from.as_str()),
- dr_types::parse_date(to.as_str()),
- ) else {
- w.set_library_range_invalid(true);
- return;
- };
+ // Both ends, or neither. A range with one end parsed and the other
+ // silently dropped is a filter nobody asked for, and the grid
+ // going empty is a poor way to find out a date was mistyped.
+ let (Some(from), Some(to)) = (
+ dr_types::parse_date(from.as_str()),
+ dr_types::parse_date(to.as_str()),
+ ) else {
+ w.global::().set_library_range_invalid(true);
+ return;
+ };
- // Typed the other way round is a slip, not an error: the user has
- // said which two days they mean and there is exactly one range
- // between them.
- let (from, to) = if from <= to { (from, to) } else { (to, from) };
+ // Typed the other way round is a slip, not an error: the user has
+ // said which two days they mean and there is exactly one range
+ // between them.
+ let (from, to) = if from <= to { (from, to) } else { (to, from) };
- {
- let mut f = ctl.filter.borrow_mut();
- f.captured_from = Some(from);
- // Inclusive of the last day. "To the 5th" means the whole of
- // the 5th — `parse_date` returns its midnight, and a range
- // ending there would exclude every photograph taken on the day
- // the user named. The same rule `dragged_range` applies.
- f.captured_to = Some(to + 86_400 - 1);
- }
- w.set_library_range_invalid(false);
- w.set_library_range_active(true);
- show_range(&w, &ctl);
- refilter(&w, &ctl);
- });
+ {
+ let mut f = ctl.filter.borrow_mut();
+ f.captured_from = Some(from);
+ // Inclusive of the last day. "To the 5th" means the whole of
+ // the 5th — `parse_date` returns its midnight, and a range
+ // ending there would exclude every photograph taken on the day
+ // the user named. The same rule `dragged_range` applies.
+ f.captured_to = Some(to + 86_400 - 1);
+ }
+ w.global::().set_library_range_invalid(false);
+ w.global::().set_library_range_active(true);
+ show_range(&w, &ctl);
+ refilter(&w, &ctl);
+ });
}
}
@@ -384,14 +409,16 @@ pub(super) fn wire_filter_scope_and_offline(
{
let weak = window.as_weak();
let ctl = ctl.clone();
- window.on_library_toggle_local_only(move || {
- let Some(w) = weak.upgrade() else { return };
- let on = !ctl.local_only();
- ctl.set_local_only(on);
- ctl.filter.borrow_mut().local_only = on;
- w.set_library_local_only(on);
- refilter(&w, &ctl);
- });
+ window
+ .global::()
+ .on_library_toggle_local_only(move || {
+ let Some(w) = weak.upgrade() else { return };
+ let on = !ctl.local_only();
+ ctl.set_local_only(on);
+ ctl.filter.borrow_mut().local_only = on;
+ w.global::().set_library_local_only(on);
+ refilter(&w, &ctl);
+ });
}
// TRACES: FR-NC-6a
@@ -403,13 +430,15 @@ pub(super) fn wire_filter_scope_and_offline(
{
let weak = window.as_weak();
let ctl = ctl.clone();
- window.on_library_toggle_pin_scope(move || {
- let Some(w) = weak.upgrade() else { return };
- let Some(scope) = *ctl.scope.borrow() else {
- return;
- };
- open_offline_prompt(&w, &ctl, scope);
- });
+ window
+ .global::()
+ .on_library_toggle_pin_scope(move || {
+ let Some(w) = weak.upgrade() else { return };
+ let Some(scope) = *ctl.scope.borrow() else {
+ return;
+ };
+ open_offline_prompt(&w, &ctl, scope);
+ });
}
// TRACES: FR-NC-6a | FR-UI-4
@@ -466,14 +495,16 @@ pub(super) fn wire_filter_scope_and_offline(
let weak = window.as_weak();
let ctl = ctl.clone();
let coll_ctl = coll_ctl.clone();
- window.on_library_retry_connection(move || {
- let Some(w) = weak.upgrade() else { return };
- log::info!("retrying the connection at the user's request");
- // A rescan is the probe: it is the same request the scan worker
- // makes, so a success proves reachability and repopulates the
- // catalog in one pass rather than proving it twice.
- start_rescan(&w, &ctl, &coll_ctl);
- });
+ window
+ .global::()
+ .on_library_retry_connection(move || {
+ let Some(w) = weak.upgrade() else { return };
+ log::info!("retrying the connection at the user's request");
+ // A rescan is the probe: it is the same request the scan worker
+ // makes, so a success proves reachability and repopulates the
+ // catalog in one pass rather than proving it twice.
+ start_rescan(&w, &ctl, &coll_ctl);
+ });
}
}
@@ -500,7 +531,9 @@ fn drop_eyes_open_without_people(window: &AppWindow, ctl: &Rc
let mut f = ctl.filter.borrow_mut();
if f.people.is_empty() && f.eyes_open {
f.eyes_open = false;
- window.set_library_filter_eyes_open(false);
+ window
+ .global::()
+ .set_library_filter_eyes_open(false);
}
}
@@ -508,6 +541,7 @@ pub(super) fn push_people_chips(window: &AppWindow, ctl: &Rc)
let ids = ctl.filter.borrow().people.clone();
if ids.is_empty() {
window
+ .global::()
.set_library_filter_people(slint::ModelRc::new(slint::VecModel::from(
Vec::::new(),
)));
@@ -552,11 +586,15 @@ pub(super) fn push_people_chips(window: &AppWindow, ctl: &Rc)
})
.collect();
- window.set_library_filter_people(slint::ModelRc::new(slint::VecModel::from(chips)));
- window.set_library_filter_people_all(matches!(
- ctl.filter.borrow().people_mode,
- library::PeopleMode::All
- ));
+ window
+ .global::()
+ .set_library_filter_people(slint::ModelRc::new(slint::VecModel::from(chips)));
+ window
+ .global::()
+ .set_library_filter_people_all(matches!(
+ ctl.filter.borrow().people_mode,
+ library::PeopleMode::All
+ ));
push_people_roster(window, ctl);
}
@@ -621,7 +659,9 @@ fn push_people_roster(window: &AppWindow, ctl: &Rc) {
rows.sort_by_key(|(unnamed, faces, _)| (*unnamed, -faces));
let rows: Vec = rows.into_iter().map(|(_, _, chip)| chip).collect();
- window.set_library_people(slint::ModelRc::new(slint::VecModel::from(rows)));
+ window
+ .global::()
+ .set_library_people(slint::ModelRc::new(slint::VecModel::from(rows)));
}
pub(super) fn refilter(window: &AppWindow, ctl: &Rc) {
@@ -687,10 +727,14 @@ fn show_range(window: &AppWindow, ctl: &Rc) {
let text = |t: Option| -> slint::SharedString {
t.map(dr_types::format_date).unwrap_or_default().into()
};
- window.set_library_range_from(text(f.captured_from));
+ window
+ .global::()
+ .set_library_range_from(text(f.captured_from));
// The stored end is the last second of the closing day; naming that day is
// what the user typed and what they should read back.
- window.set_library_range_to(text(f.captured_to.map(|t| t - 86_400 + 1)));
+ window
+ .global::()
+ .set_library_range_to(text(f.captured_to.map(|t| t - 86_400 + 1)));
}
#[cfg(test)]
diff --git a/ui/dr-ui/src/library_ui/grid.rs b/ui/dr-ui/src/library_ui/grid.rs
index 4c6c0e3..1533b07 100644
--- a/ui/dr-ui/src/library_ui/grid.rs
+++ b/ui/dr-ui/src/library_ui/grid.rs
@@ -12,7 +12,7 @@ use std::rc::Rc;
use slint::{ComponentHandle, Model as _};
use crate::AppWindow;
-use crate::{GestureRow, View};
+use crate::{GestureRow, Library, View};
use super::controller::{
LibraryController, OpenImage, MAX_CELL_SIZE, MIN_CELL_SIZE, MIN_WINDOW, SCREENFULS,
@@ -49,7 +49,7 @@ fn move_cursor(
delta: i32,
extend: bool,
) {
- let total = window.get_library_total().max(0) as usize;
+ let total = window.global::().get_library_total().max(0) as usize;
if total == 0 {
return;
}
@@ -93,11 +93,11 @@ fn place_cursor(
// quarter in, exactly as a scroll does it, so continuing in the same
// direction has loaded cells to move into rather than another reload on
// the very next press.
- let loaded = window.get_library_cells().row_count();
+ let loaded = window.global::().get_library_cells().row_count();
let offset = *ctl.offset.borrow();
if at < offset || at >= offset + loaded {
let size = *ctl.window.borrow();
- let total = window.get_library_total().max(0) as usize;
+ let total = window.global::().get_library_total().max(0) as usize;
*ctl.offset.borrow_mut() = window_start(at, size, total);
load_window(window, ctl);
}
@@ -122,7 +122,7 @@ fn place_cursor(
}
crate::collections_ui::select_row(window, coll, &ids, offset, row, false, extend);
- window.set_library_cursor(at as i32);
+ window.global::().set_library_cursor(at as i32);
}
/// Say where in the library the photograph now open sits.
@@ -136,7 +136,7 @@ fn place_cursor(
fn report_position(window: &AppWindow, ctl: &Rc, row: usize) {
let offset = *ctl.offset.borrow();
window.set_index((offset + row) as i32);
- window.set_total(window.get_library_total());
+ window.set_total(window.global::().get_library_total());
}
/// Connect the grid's callbacks.
@@ -175,25 +175,29 @@ pub fn wire(
// claims the gesture before the delay it would forward after. Seeding it
// here means the stars are on screen before the first touch rather than
// after it, which is the whole point of showing them.
- window.set_library_touched(cfg!(target_os = "android"));
+ window
+ .global::()
+ .set_library_touched(cfg!(target_os = "android"));
// TRACES: FR-UI-4
// The gesture reference. Pushed once, here, rather than on demand: the
// table is a compiled-in constant, so there is nothing to be fresh about
// and nothing to recompute — a callback to fill it would only be a way for
// it to be empty the first time the sheet opens.
- window.set_library_gestures(slint::ModelRc::new(slint::VecModel::from(
- crate::gestures::rows()
- .into_iter()
- .map(|r| GestureRow {
- heading: r.heading.into(),
- title: r.title.into(),
- touch: r.touch.into(),
- pointer: r.pointer.into(),
- keys: r.keys.into(),
- })
- .collect::>(),
- )));
+ window
+ .global::()
+ .set_library_gestures(slint::ModelRc::new(slint::VecModel::from(
+ crate::gestures::rows()
+ .into_iter()
+ .map(|r| GestureRow {
+ heading: r.heading.into(),
+ title: r.title.into(),
+ touch: r.touch.into(),
+ pointer: r.pointer.into(),
+ keys: r.keys.into(),
+ })
+ .collect::>(),
+ )));
// Shared rather than moved: a click and `Return` both open an image, and
// they are two callbacks.
@@ -209,42 +213,44 @@ pub fn wire(
let ctl = ctl.clone();
let coll_for_click = coll_ctl.clone();
let on_open_image = on_open_image.clone();
- window.on_library_cell_clicked(move |i| {
- let Some(w) = weak.upgrade() else { return };
+ window
+ .global::()
+ .on_library_cell_clicked(move |i| {
+ let Some(w) = weak.upgrade() else { return };
- // The press stayed put, so it was a tap and not a drag: whatever it
- // held back can be applied now. See `collections_ui::Press`.
- crate::collections_ui::commit_press(&w, &coll_for_click, &ctl.visible_ids());
+ // The press stayed put, so it was a tap and not a drag: whatever it
+ // held back can be applied now. See `collections_ui::Press`.
+ crate::collections_ui::commit_press(&w, &coll_for_click, &ctl.visible_ids());
- // A ctrl- or shift-click is a selection gesture. Opening the image
- // too would throw the user out of the grid mid-selection.
- if coll_for_click.press_was_modified() {
- return;
- }
+ // A ctrl- or shift-click is a selection gesture. Opening the image
+ // too would throw the user out of the grid mid-selection.
+ if coll_for_click.press_was_modified() {
+ return;
+ }
- let path = ctl.paths.borrow().get(i as usize).cloned();
- if let Some(path) = path {
- // Leave the grid for the develop view. The status bar's
- // "‹ Library" button comes back here.
- w.set_active_view(View::Develop);
- // Which cell the develop view is now showing, so the photo
- // roll opens marking it rather than marking nothing.
- w.set_library_roll_current(i);
- // A develop session begins here, so the roll centres on this
- // photograph the first time it settles rather than merely
- // scrolling it into view at one edge. Raised here and not in
- // `on_library_roll_pick`, which is a step *within* a session —
- // see `PhotoRoll::centre-request`.
- w.set_library_roll_centre(true);
- on_open_image(path);
- report_position(&w, &ctl, i as usize);
- // TRACES: FR-UI-8
- // Written now rather than on a settle: which view you are in is
- // the field a debounce is most likely to lose, and quitting
- // straight from develop is exactly the case worth getting right.
- write_place(&w, &ctl);
- }
- });
+ let path = ctl.paths.borrow().get(i as usize).cloned();
+ if let Some(path) = path {
+ // Leave the grid for the develop view. The status bar's
+ // "‹ Library" button comes back here.
+ w.set_active_view(View::Develop);
+ // Which cell the develop view is now showing, so the photo
+ // roll opens marking it rather than marking nothing.
+ w.global::().set_library_roll_current(i);
+ // A develop session begins here, so the roll centres on this
+ // photograph the first time it settles rather than merely
+ // scrolling it into view at one edge. Raised here and not in
+ // `on_library_roll_pick`, which is a step *within* a session —
+ // see `PhotoRoll::centre-request`.
+ w.global::().set_library_roll_centre(true);
+ on_open_image(path);
+ report_position(&w, &ctl, i as usize);
+ // TRACES: FR-UI-8
+ // Written now rather than on a settle: which view you are in is
+ // the field a debounce is most likely to lose, and quitting
+ // straight from develop is exactly the case worth getting right.
+ write_place(&w, &ctl);
+ }
+ });
}
// TRACES: FR-UI-4
@@ -259,12 +265,12 @@ pub fn wire(
let weak = window.as_weak();
let ctl = ctl.clone();
let on_open_image = on_open_image.clone();
- window.on_library_roll_pick(move |i| {
+ window.global::().on_library_roll_pick(move |i| {
let Some(w) = weak.upgrade() else { return };
let Some(path) = ctl.paths.borrow().get(i as usize).cloned() else {
return;
};
- w.set_library_roll_current(i);
+ w.global::().set_library_roll_current(i);
on_open_image(path);
report_position(&w, &ctl, i as usize);
// TRACES: FR-UI-8
@@ -307,10 +313,12 @@ fn wire_grid_cursor_and_zoom(
let weak = window.as_weak();
let ctl = ctl.clone();
let coll = coll_ctl.clone();
- window.on_library_move_cursor(move |delta, extend| {
- let Some(w) = weak.upgrade() else { return };
- move_cursor(&w, &ctl, &coll, delta, extend);
- });
+ window
+ .global::()
+ .on_library_move_cursor(move |delta, extend| {
+ let Some(w) = weak.upgrade() else { return };
+ move_cursor(&w, &ctl, &coll, delta, extend);
+ });
}
{
@@ -318,7 +326,7 @@ fn wire_grid_cursor_and_zoom(
let ctl = ctl.clone();
let coll = coll_ctl.clone();
let on_open = on_open_image.clone();
- window.on_library_open_cursor(move || {
+ window.global::().on_library_open_cursor(move || {
let Some(w) = weak.upgrade() else { return };
// The cursor is a library ordinal and `paths` is the loaded
// window, so the row is the difference. A cursor outside the
@@ -333,8 +341,9 @@ fn wire_grid_cursor_and_zoom(
w.set_active_view(View::Develop);
// As on a click: the roll marks what is open, and centres on it
// because this too begins a session.
- w.set_library_roll_current(row.unwrap_or(0) as i32);
- w.set_library_roll_centre(true);
+ w.global::()
+ .set_library_roll_current(row.unwrap_or(0) as i32);
+ w.global::().set_library_roll_centre(true);
on_open(path);
report_position(&w, &ctl, row.unwrap_or(0));
write_place(&w, &ctl);
@@ -350,33 +359,35 @@ fn wire_grid_cursor_and_zoom(
{
let weak = window.as_weak();
let ctl = ctl.clone();
- window.on_library_zoom_cells(move |delta| {
- let Some(w) = weak.upgrade() else { return };
+ window
+ .global::()
+ .on_library_zoom_cells(move |delta| {
+ let Some(w) = weak.upgrade() else { return };
- let current = w.get_library_cell_size();
- let next = if delta > 0 {
- current * 1.25
- } else {
- current / 1.25
- }
- .clamp(MIN_CELL_SIZE, MAX_CELL_SIZE);
+ let current = w.global::().get_library_cell_size();
+ let next = if delta > 0 {
+ current * 1.25
+ } else {
+ current / 1.25
+ }
+ .clamp(MIN_CELL_SIZE, MAX_CELL_SIZE);
- if (next - current).abs() < 0.5 {
- return;
- }
- w.set_library_cell_size(next);
+ if (next - current).abs() < 0.5 {
+ return;
+ }
+ w.global::().set_library_cell_size(next);
- // No need to forget anything on a class change: the class is part
- // of the request key, so cells that now want the large resolution
- // simply miss and ask for it, while the 256px ones they already
- // hold stay served.
- //
- // Deferred, like every other geometry change. This one was still
- // reloading inline — a full catalog re-read and model rebuild per
- // step, which is what a wheel spun through six steps paid six
- // times over.
- schedule_reload(&w, &ctl);
- });
+ // No need to forget anything on a class change: the class is part
+ // of the request key, so cells that now want the large resolution
+ // simply miss and ask for it, while the 256px ones they already
+ // hold stay served.
+ //
+ // Deferred, like every other geometry change. This one was still
+ // reloading inline — a full catalog re-read and model rebuild per
+ // step, which is what a wheel spun through six steps paid six
+ // times over.
+ schedule_reload(&w, &ctl);
+ });
}
// TRACES: FR-UI-4
@@ -391,20 +402,22 @@ fn wire_grid_cursor_and_zoom(
{
let weak = window.as_weak();
let ctl = ctl.clone();
- window.on_library_pinch_cells(move |ratio| {
- let Some(w) = weak.upgrade() else { return };
- if !(ratio.is_finite() && ratio > 0.0) {
- return;
- }
+ window
+ .global::()
+ .on_library_pinch_cells(move |ratio| {
+ let Some(w) = weak.upgrade() else { return };
+ if !(ratio.is_finite() && ratio > 0.0) {
+ return;
+ }
- let current = w.get_library_cell_size();
- let next = (current * ratio).clamp(MIN_CELL_SIZE, MAX_CELL_SIZE);
- if (next - current).abs() < 0.5 {
- return;
- }
- w.set_library_cell_size(next);
- schedule_reload(&w, &ctl);
- });
+ let current = w.global::().get_library_cell_size();
+ let next = (current * ratio).clamp(MIN_CELL_SIZE, MAX_CELL_SIZE);
+ if (next - current).abs() < 0.5 {
+ return;
+ }
+ w.global::().set_library_cell_size(next);
+ schedule_reload(&w, &ctl);
+ });
}
// TRACES: FR-UI-4
@@ -418,10 +431,12 @@ fn wire_grid_cursor_and_zoom(
let weak = window.as_weak();
let ctl = ctl.clone();
let coll = coll_ctl.clone();
- window.on_library_pinch_started(move || {
- let Some(w) = weak.upgrade() else { return };
- crate::collections_ui::cancel_press(&w, &coll, &ctl.visible_ids());
- });
+ window
+ .global::()
+ .on_library_pinch_started(move || {
+ let Some(w) = weak.upgrade() else { return };
+ crate::collections_ui::cancel_press(&w, &coll, &ctl.visible_ids());
+ });
}
}
@@ -433,7 +448,7 @@ fn wire_grid_sync_and_load(window: &AppWindow, ctl: &Rc) {
{
let weak = window.as_weak();
let ctl = ctl.clone();
- window.on_library_sync_now(move || {
+ window.global::().on_library_sync_now(move || {
if let Some(w) = weak.upgrade() {
start_derived_sync(&w, &ctl);
}
@@ -446,11 +461,13 @@ fn wire_grid_sync_and_load(window: &AppWindow, ctl: &Rc) {
{
let weak = window.as_weak();
let ctl = ctl.clone();
- window.on_library_thumbnail_all(move || {
- if let Some(w) = weak.upgrade() {
- start_thumbnail_sweep(&w, &ctl);
- }
- });
+ window
+ .global::()
+ .on_library_thumbnail_all(move || {
+ if let Some(w) = weak.upgrade() {
+ start_thumbnail_sweep(&w, &ctl);
+ }
+ });
}
// A column-count change moves which cells begin a row, and month headings
@@ -462,25 +479,27 @@ fn wire_grid_sync_and_load(window: &AppWindow, ctl: &Rc) {
{
let weak = window.as_weak();
let ctl = ctl.clone();
- window.on_library_columns_changed(move || {
- if let Some(w) = weak.upgrade() {
- if !w.get_library_visible() {
- return;
- }
+ window
+ .global::()
+ .on_library_columns_changed(move || {
+ if let Some(w) = weak.upgrade() {
+ if !w.get_library_visible() {
+ return;
+ }
- // Deferred, and re-anchored when it lands — see
- // [`schedule_reload`]. A column change moves every cell in the
- // grid, because a cell is drawn at its absolute place in the
- // library and the row that resolves to is `index / columns`.
- // The viewport does not move with them, so without the
- // re-anchor the view is left pointing at rows the loaded window
- // no longer covers and the grid draws nothing at all — the
- // "gallery randomly goes blank until I scroll" report, whose
- // triggers are a resize, the sidebar opening, a zoom step, or
- // turning the tablet over.
- schedule_reload(&w, &ctl);
- }
- });
+ // Deferred, and re-anchored when it lands — see
+ // [`schedule_reload`]. A column change moves every cell in the
+ // grid, because a cell is drawn at its absolute place in the
+ // library and the row that resolves to is `index / columns`.
+ // The viewport does not move with them, so without the
+ // re-anchor the view is left pointing at rows the loaded window
+ // no longer covers and the grid draws nothing at all — the
+ // "gallery randomly goes blank until I scroll" report, whose
+ // triggers are a resize, the sidebar opening, a zoom step, or
+ // turning the tablet over.
+ schedule_reload(&w, &ctl);
+ }
+ });
}
// The viewport changed size, so the window it can usefully hold changed
@@ -489,23 +508,25 @@ fn wire_grid_sync_and_load(window: &AppWindow, ctl: &Rc) {
{
let weak = window.as_weak();
let ctl = ctl.clone();
- window.on_library_viewport_cells(move |on_screen| {
- let Some(w) = weak.upgrade() else { return };
- if !w.get_library_visible() {
- return;
- }
- let on_screen = (on_screen.max(0) as usize).max(1);
- let window_size = (on_screen * SCREENFULS).max(MIN_WINDOW);
- if window_size == *ctl.window.borrow() && on_screen == ctl.viewport_cells.get() {
- return;
- }
- ctl.viewport_cells.set(on_screen);
- *ctl.window.borrow_mut() = window_size;
- // Coalesced with the column change that almost always accompanies
- // it: resizing the cells alters both, and reloading once per report
- // meant two full rebuilds per zoom step.
- schedule_reload(&w, &ctl);
- });
+ window
+ .global::()
+ .on_library_viewport_cells(move |on_screen| {
+ let Some(w) = weak.upgrade() else { return };
+ if !w.get_library_visible() {
+ return;
+ }
+ let on_screen = (on_screen.max(0) as usize).max(1);
+ let window_size = (on_screen * SCREENFULS).max(MIN_WINDOW);
+ if window_size == *ctl.window.borrow() && on_screen == ctl.viewport_cells.get() {
+ return;
+ }
+ ctl.viewport_cells.set(on_screen);
+ *ctl.window.borrow_mut() = window_size;
+ // Coalesced with the column change that almost always accompanies
+ // it: resizing the cells alters both, and reloading once per report
+ // meant two full rebuilds per zoom step.
+ schedule_reload(&w, &ctl);
+ });
}
// Scrolling moves the loaded window through the library.
@@ -515,118 +536,122 @@ fn wire_grid_sync_and_load(window: &AppWindow, ctl: &Rc) {
{
let weak = window.as_weak();
let ctl = ctl.clone();
- window.on_library_scrolled(move |first_visible| {
- let Some(w) = weak.upgrade() else { return };
- let first_visible = first_visible.max(0) as usize;
+ window
+ .global::()
+ .on_library_scrolled(move |first_visible| {
+ let Some(w) = weak.upgrade() else { return };
+ let first_visible = first_visible.max(0) as usize;
- // **A report from a grid that is not on screen is not a scroll.**
- //
- // The grid is gated on an `if`, so leaving it tears the whole
- // subtree down — and a Flickable being destroyed passes its viewport
- // through zero on the way out, which arrives here indistinguishable
- // from the user having flung the grid to the top. Everything below
- // then ran on the way *into* develop: the loaded window was reset to
- // offset zero, the model was rebuilt against the first rows of the
- // library, and a thumbnail batch was issued for photographs nobody
- // had asked to see. Those rebuilds landed while the grid was still
- // being taken apart, which is what flashed the library over the
- // develop view for the first few frames after a click — and on a
- // remote library it also spent a burst of requests on the top of the
- // catalog every single time an image was opened.
- //
- // **`library-visible`, not `show-library`, and the difference is the
- // whole bug.** `show-library` says "the library rather than develop"
- // and stays true while Settings, Import, People or the launch screen
- // replaces the window — all four of which take the grid down just as
- // opening an image does. So the teardown's scroll-to-zero passed this
- // guard, `resume_at` was set to 0, and coming back from any of those
- // four screens landed at the top of the library however deep in it the
- // user had been. The property is computed once in `app.slint` beside
- // the `if` it is spelled from, so the two cannot drift apart again.
- //
- // The guard used to cover only `resume_at`, for a narrower version
- // of the same reason. It belongs over the whole handler.
- if !w.get_library_visible() {
- return;
- }
+ // **A report from a grid that is not on screen is not a scroll.**
+ //
+ // The grid is gated on an `if`, so leaving it tears the whole
+ // subtree down — and a Flickable being destroyed passes its viewport
+ // through zero on the way out, which arrives here indistinguishable
+ // from the user having flung the grid to the top. Everything below
+ // then ran on the way *into* develop: the loaded window was reset to
+ // offset zero, the model was rebuilt against the first rows of the
+ // library, and a thumbnail batch was issued for photographs nobody
+ // had asked to see. Those rebuilds landed while the grid was still
+ // being taken apart, which is what flashed the library over the
+ // develop view for the first few frames after a click — and on a
+ // remote library it also spent a burst of requests on the top of the
+ // catalog every single time an image was opened.
+ //
+ // **`library-visible`, not `show-library`, and the difference is the
+ // whole bug.** `show-library` says "the library rather than develop"
+ // and stays true while Settings, Import, People or the launch screen
+ // replaces the window — all four of which take the grid down just as
+ // opening an image does. So the teardown's scroll-to-zero passed this
+ // guard, `resume_at` was set to 0, and coming back from any of those
+ // four screens landed at the top of the library however deep in it the
+ // user had been. The property is computed once in `app.slint` beside
+ // the `if` it is spelled from, so the two cannot drift apart again.
+ //
+ // The guard used to cover only `resume_at`, for a narrower version
+ // of the same reason. It belongs over the whole handler.
+ if !w.get_library_visible() {
+ return;
+ }
- // Remember where the view is, so leaving for the develop view and
- // coming back returns here. Latched on every event rather than read
- // at departure: by the time the grid is hidden its scroll position
- // is only in the Flickable, which is about to be destroyed.
- ctl.resume_at.set(first_visible);
+ // Remember where the view is, so leaving for the develop view and
+ // coming back returns here. Latched on every event rather than read
+ // at departure: by the time the grid is hidden its scroll position
+ // is only in the Flickable, which is about to be destroyed.
+ ctl.resume_at.set(first_visible);
- // TRACES: FR-UI-8
- // And where the *next launch* will look for it. Debounced: a flick
- // reports several of these per screenful.
- note_place(&w, &ctl);
+ // TRACES: FR-UI-8
+ // And where the *next launch* will look for it. Debounced: a flick
+ // reports several of these per screenful.
+ note_place(&w, &ctl);
- // The same position where a rebuilt grid will look for it.
- //
- // `scroll-to` is read by `seek()`, which runs on a `scroll-token`
- // change and on `init` — so writing it here without bumping the
- // token cannot move the grid that is on screen, and *is* what the
- // next one reads when it is built. That is every route back to the
- // grid at once: Settings, Import, People and the launch screen all
- // tear the subtree down and rebuild it, and none of them goes
- // through `on_back_to_library` to have the position replayed by
- // hand. Without this they each rebuilt against whatever `scroll-to`
- // was last *set* to — a stale scrub, or zero — and landed there.
- w.set_library_scroll_to(first_visible as i32);
+ // The same position where a rebuilt grid will look for it.
+ //
+ // `scroll-to` is read by `seek()`, which runs on a `scroll-token`
+ // change and on `init` — so writing it here without bumping the
+ // token cannot move the grid that is on screen, and *is* what the
+ // next one reads when it is built. That is every route back to the
+ // grid at once: Settings, Import, People and the launch screen all
+ // tear the subtree down and rebuild it, and none of them goes
+ // through `on_back_to_library` to have the position replayed by
+ // hand. Without this they each rebuilt against whatever `scroll-to`
+ // was last *set* to — a stale scrub, or zero — and landed there.
+ w.global::()
+ .set_library_scroll_to(first_visible as i32);
- // Move the timeline marker with the view. Scrolling the grid is a
- // way of moving through time just as scrubbing is, and a marker
- // that only ever moved on a scrub sat still while the photographs
- // beside it advanced by months — the axis said "when you are" and
- // was wrong the moment the user touched the wheel.
- //
- // This runs before the reload guard below, which fires only a few
- // times per screenful; the marker has to follow every event or it
- // would advance in visible jerks.
- //
- // Only the marker is moved, not the whole histogram: rebuilding
- // the bars means a `GROUP BY strftime` aggregate over the library,
- // far too much for every event of a flick. The bars do not change
- // as the grid scrolls anyway — only where the marker sits on them.
- //
- // Re-running the scrub would be wrong for a second reason: it sets
- // `scroll-to`, which would drive the grid from its own scroll.
- {
- let borrow = ctl.catalog.borrow();
- if let Some(catalog) = borrow.as_ref() {
- if let Some(when) = capture_time_at(&ctl, catalog, first_visible) {
- *ctl.current_bucket.borrow_mut() = Some(when);
+ // Move the timeline marker with the view. Scrolling the grid is a
+ // way of moving through time just as scrubbing is, and a marker
+ // that only ever moved on a scrub sat still while the photographs
+ // beside it advanced by months — the axis said "when you are" and
+ // was wrong the moment the user touched the wheel.
+ //
+ // This runs before the reload guard below, which fires only a few
+ // times per screenful; the marker has to follow every event or it
+ // would advance in visible jerks.
+ //
+ // Only the marker is moved, not the whole histogram: rebuilding
+ // the bars means a `GROUP BY strftime` aggregate over the library,
+ // far too much for every event of a flick. The bars do not change
+ // as the grid scrolls anyway — only where the marker sits on them.
+ //
+ // Re-running the scrub would be wrong for a second reason: it sets
+ // `scroll-to`, which would drive the grid from its own scroll.
+ {
+ let borrow = ctl.catalog.borrow();
+ if let Some(catalog) = borrow.as_ref() {
+ if let Some(when) = capture_time_at(&ctl, catalog, first_visible) {
+ *ctl.current_bucket.borrow_mut() = Some(when);
- let zoom = *ctl.timeline_zoom.borrow();
- let centre = *ctl.timeline_centre.borrow();
- if let Some(full) = catalog_span(catalog, &ctl) {
- let (from, to) = zoomed_span(full, zoom, centre);
- w.set_library_current_bucket(when as i32);
- w.set_library_current_fraction(
- ((when - from) as f64 / (to - from).max(1) as f64).clamp(0.0, 1.0)
- as f32,
- );
- w.set_library_timeline_anchored(true);
+ let zoom = *ctl.timeline_zoom.borrow();
+ let centre = *ctl.timeline_centre.borrow();
+ if let Some(full) = catalog_span(catalog, &ctl) {
+ let (from, to) = zoomed_span(full, zoom, centre);
+ w.global::()
+ .set_library_current_bucket(when as i32);
+ w.global::().set_library_current_fraction(
+ ((when - from) as f64 / (to - from).max(1) as f64)
+ .clamp(0.0, 1.0) as f32,
+ );
+ w.global::().set_library_timeline_anchored(true);
+ }
}
}
}
- }
- // Centre the window on the view, so scrolling either way has
- // loaded rows ahead of it rather than only below.
- let Some(offset) = window_move(
- first_visible,
- *ctl.offset.borrow(),
- *ctl.window.borrow(),
- ctl.viewport_cells.get(),
- w.get_library_total().max(0) as usize,
- ) else {
- return;
- };
+ // Centre the window on the view, so scrolling either way has
+ // loaded rows ahead of it rather than only below.
+ let Some(offset) = window_move(
+ first_visible,
+ *ctl.offset.borrow(),
+ *ctl.window.borrow(),
+ ctl.viewport_cells.get(),
+ w.global::().get_library_total().max(0) as usize,
+ ) else {
+ return;
+ };
- *ctl.offset.borrow_mut() = offset;
- load_window(&w, &ctl);
- });
+ *ctl.offset.borrow_mut() = offset;
+ load_window(&w, &ctl);
+ });
}
}
@@ -643,7 +668,7 @@ fn wire_grid_routes(
// folder could not be changed without clearing stored state by hand.
{
let weak = window.as_weak();
- window.on_library_change(move || {
+ window.global::().on_library_change(move || {
if let Some(w) = weak.upgrade() {
w.set_active_view(View::Launch);
}
@@ -692,7 +717,7 @@ fn wire_grid_routes(
let weak = window.as_weak();
let ctl = ctl.clone();
let coll_ctl = coll_ctl.clone();
- window.on_library_rescan(move || {
+ window.global::().on_library_rescan(move || {
let Some(w) = weak.upgrade() else { return };
start_rescan(&w, &ctl, &coll_ctl);
});
diff --git a/ui/dr-ui/src/library_ui/offline.rs b/ui/dr-ui/src/library_ui/offline.rs
index ba726d7..f3acb30 100644
--- a/ui/dr-ui/src/library_ui/offline.rs
+++ b/ui/dr-ui/src/library_ui/offline.rs
@@ -13,7 +13,7 @@ use dr_catalog::Catalog;
use slint::ComponentHandle;
use crate::library;
-use crate::AppWindow;
+use crate::{AppWindow, Library};
use super::controller::{stop, LibraryController};
@@ -115,7 +115,9 @@ pub(super) fn open_offline_prompt(
let ids = match dr_catalog::collections::descendants(catalog.connection(), id) {
Ok(ids) => ids,
Err(e) => {
- window.set_library_error(format!("resolving collection: {e}").into());
+ window
+ .global::()
+ .set_library_error(format!("resolving collection: {e}").into());
return;
}
};
@@ -180,7 +182,7 @@ pub(super) fn open_offline_prompt(
);
window.set_offline_prompt_can_keep(summary.missing() > 0);
window.set_offline_prompt_can_release(summary.held > 0);
- window.set_offline_prompt_busy(window.get_library_pin_total() > 0);
+ window.set_offline_prompt_busy(window.global::().get_library_pin_total() > 0);
}
/// Close the offline question without answering it.
@@ -208,7 +210,9 @@ pub(super) fn keep_collection_offline(
return;
};
let Some(cache) = ctl.cache() else {
- window.set_library_error("No cache directory for this library.".into());
+ window
+ .global::()
+ .set_library_error("No cache directory for this library.".into());
return;
};
@@ -220,26 +224,34 @@ pub(super) fn keep_collection_offline(
let ids = match dr_catalog::collections::descendants(catalog.connection(), id) {
Ok(ids) => ids,
Err(e) => {
- window.set_library_error(format!("resolving collection: {e}").into());
+ window
+ .global::()
+ .set_library_error(format!("resolving collection: {e}").into());
return;
}
};
let images = collection_images(catalog, &ids);
if images.is_empty() {
- window.set_library_error("Nothing in that collection to keep offline.".into());
+ window
+ .global::()
+ .set_library_error("Nothing in that collection to keep offline.".into());
return;
}
if let Err(e) = cache.pin(catalog.connection(), &images) {
- window.set_library_error(format!("pinning: {e}").into());
+ window
+ .global::()
+ .set_library_error(format!("pinning: {e}").into());
return;
}
images
};
log::info!("pinned {} image(s) for offline use", images.len());
- window.set_library_error(slint::SharedString::new());
+ window
+ .global::()
+ .set_library_error(slint::SharedString::new());
if ctl.scope.borrow().as_ref() == Some(&id) {
- window.set_library_scope_pinned(true);
+ window.global::().set_library_scope_pinned(true);
}
close_offline_prompt(window, ctl);
start_pin_fetch(window, ctl);
@@ -264,7 +276,9 @@ pub(super) fn release_collection_offline(
return;
};
let Some(cache) = ctl.cache() else {
- window.set_library_error("No cache directory for this library.".into());
+ window
+ .global::()
+ .set_library_error("No cache directory for this library.".into());
return;
};
@@ -276,7 +290,9 @@ pub(super) fn release_collection_offline(
let ids = match dr_catalog::collections::descendants(catalog.connection(), id) {
Ok(ids) => ids,
Err(e) => {
- window.set_library_error(format!("resolving collection: {e}").into());
+ window
+ .global::()
+ .set_library_error(format!("resolving collection: {e}").into());
return;
}
};
@@ -284,7 +300,9 @@ pub(super) fn release_collection_offline(
let outcome = match cache.release(catalog.connection(), &images) {
Ok(r) => r,
Err(e) => {
- window.set_library_error(format!("removing local copies: {e}").into());
+ window
+ .global::()
+ .set_library_error(format!("removing local copies: {e}").into());
return;
}
};
@@ -312,8 +330,10 @@ pub(super) fn release_collection_offline(
"released {count} image(s), freeing {}",
crate::activity::describe_bytes(freed)
);
- window.set_library_error(slint::SharedString::new());
- window.set_library_status(
+ window
+ .global::()
+ .set_library_error(slint::SharedString::new());
+ window.global::().set_library_status(
format!(
"Removed local copies · {} freed",
crate::activity::describe_bytes(freed)
@@ -322,13 +342,13 @@ pub(super) fn release_collection_offline(
.into(),
);
if ctl.scope.borrow().as_ref() == Some(&id) {
- window.set_library_scope_pinned(false);
+ window.global::().set_library_scope_pinned(false);
}
// A download that was still running for this collection has just had its
// reason withdrawn; the worker checks `pending_pins` per file, so it stops
// finding work rather than being killed.
- window.set_library_pin_total(0);
- window.set_library_pin_done(0);
+ window.global::().set_library_pin_total(0);
+ window.global::().set_library_pin_done(0);
close_offline_prompt(window, ctl);
refresh_local_count(window, ctl);
refresh_collection_tree(window, ctl, coll_ctl);
@@ -433,7 +453,7 @@ fn start_pin_fetch(window: &AppWindow, ctl: &Rc) {
Ok(m) => m,
Err(std::sync::mpsc::TryRecvError::Empty) => return,
Err(std::sync::mpsc::TryRecvError::Disconnected) => {
- w.set_library_pin_total(0);
+ w.global::().set_library_pin_total(0);
job.fail("stopped without finishing");
stop(&ctl_cb.pin_timer);
return;
@@ -442,13 +462,13 @@ fn start_pin_fetch(window: &AppWindow, ctl: &Rc) {
match msg {
library::PinMessage::Planned { total } => {
- w.set_library_pin_total(total as i32);
- w.set_library_pin_done(0);
+ w.global::().set_library_pin_total(total as i32);
+ w.global::().set_library_pin_done(0);
job.total(total);
}
library::PinMessage::Stored { done } => {
- w.set_library_pin_done(done as i32);
- job.progress(done, w.get_library_pin_total() as usize);
+ w.global::().set_library_pin_done(done as i32);
+ job.progress(done, w.global::().get_library_pin_total() as usize);
// The "On this device" count grows as they land, so
// the chip agrees with the progress line beside it.
refresh_local_count(&w, &ctl_cb);
@@ -462,8 +482,8 @@ fn start_pin_fetch(window: &AppWindow, ctl: &Rc) {
"{stored} photograph(s) · {}",
crate::activity::describe_bytes(bytes)
));
- w.set_library_pin_total(0);
- w.set_library_pin_done(0);
+ w.global::().set_library_pin_total(0);
+ w.global::().set_library_pin_done(0);
refresh_local_count(&w, &ctl_cb);
stop(&ctl_cb.pin_timer);
return;
@@ -471,7 +491,7 @@ fn start_pin_fetch(window: &AppWindow, ctl: &Rc) {
library::PinMessage::Failed { message, offline } => {
log::warn!("pin fetch stopped: {message}");
job.fail(message.clone());
- w.set_library_pin_total(0);
+ w.global::().set_library_pin_total(0);
if offline {
ctl_cb
.reachability
@@ -479,7 +499,8 @@ fn start_pin_fetch(window: &AppWindow, ctl: &Rc) {
.mark_unreachable(message, std::time::Instant::now());
refresh_offline(&w, &ctl_cb);
} else {
- w.set_library_error(format!("keeping offline: {message}").into());
+ w.global::()
+ .set_library_error(format!("keeping offline: {message}").into());
}
refresh_local_count(&w, &ctl_cb);
stop(&ctl_cb.pin_timer);
@@ -499,7 +520,9 @@ fn refresh_local_count(window: &AppWindow, ctl: &Rc) {
let Some(catalog) = borrow.as_ref() else {
return;
};
- window.set_library_local_count(library::local_original_count(catalog).unwrap_or(0) as i32);
+ window
+ .global::()
+ .set_library_local_count(library::local_original_count(catalog).unwrap_or(0) as i32);
}
/// TRACES: FR-NC-6a
@@ -552,12 +575,14 @@ pub(super) fn refresh_offline(window: &AppWindow, ctl: &Rc) {
let lost = ctl.root_lost.borrow();
let offline = reach.is_offline() || lost.is_some();
- window.set_library_offline(offline);
- window.set_library_offline_reason(match lost.as_deref() {
- Some(why) => why.into(),
- None => reach.reason().unwrap_or_default().into(),
- });
- window.set_library_offline_since(
+ window.global::().set_library_offline(offline);
+ window
+ .global::()
+ .set_library_offline_reason(match lost.as_deref() {
+ Some(why) => why.into(),
+ None => reach.reason().unwrap_or_default().into(),
+ });
+ window.global::().set_library_offline_since(
// A duration is what a network outage has and a revoked permission
// does not: "for 4 minutes" invites waiting, and waiting is precisely
// what will not help here.
@@ -575,7 +600,7 @@ pub(super) fn refresh_offline(window: &AppWindow, ctl: &Rc) {
// A stale scan error under an offline banner reports one problem twice.
if offline {
- window.set_library_error("".into());
+ window.global::().set_library_error("".into());
}
drop(reach);
@@ -655,7 +680,9 @@ fn start_outbox_drain(window: &AppWindow, ctl: &Rc) {
} else if written > 0 {
log::info!("{written} queued sidecar(s) uploaded");
job.finish(format!("{written} queued edit(s) uploaded"));
- w.set_library_status(format!("{written} queued edit(s) uploaded").into());
+ w.global::().set_library_status(
+ format!("{written} queued edit(s) uploaded").into(),
+ );
} else {
job.finish_quietly();
}
diff --git a/ui/dr-ui/src/library_ui/open.rs b/ui/dr-ui/src/library_ui/open.rs
index 7822b79..4070b69 100644
--- a/ui/dr-ui/src/library_ui/open.rs
+++ b/ui/dr-ui/src/library_ui/open.rs
@@ -18,7 +18,7 @@ use dr_types::FormatFilter;
use slint::ComponentHandle;
use crate::library::{self, ScanMessage};
-use crate::{AppWindow, View};
+use crate::{AppWindow, Library, View};
use super::controller::{stop, LibraryController};
use super::offline::refresh_offline;
@@ -57,7 +57,9 @@ pub fn open(
let conn = match store.connection(&account, crate::remote::needs_secret(&account)) {
Ok(c) => c,
Err(e) => {
- window.set_library_error(format!("credentials: {e}").into());
+ window
+ .global::()
+ .set_library_error(format!("credentials: {e}").into());
window.set_active_view(View::Library);
return;
}
@@ -79,19 +81,27 @@ pub fn open(
ctl.place_untouched.set(true);
window.set_active_view(View::Library);
- window.set_library_open(true);
- window.set_library_scanning(true);
- window.set_library_error(slint::SharedString::new());
- window.set_library_status("Starting…".into());
+ window.global::().set_library_open(true);
+ window.global::().set_library_scanning(true);
+ window
+ .global::()
+ .set_library_error(slint::SharedString::new());
+ window
+ .global::()
+ .set_library_status("Starting…".into());
// Always visible: two folders one letter apart are easy to confuse, and a
// scan of the wrong one is indistinguishable from a broken scan.
- window.set_library_root_label(library_root_label(&conn.account).into());
+ window
+ .global::()
+ .set_library_root_label(library_root_label(&conn.account).into());
// An empty filter would walk the whole tree and match nothing, which looks
// exactly like a broken scan. Say so instead.
if filter.is_empty() {
- window.set_library_scanning(false);
- window.set_library_error("No formats selected — tick at least one.".into());
+ window.global::().set_library_scanning(false);
+ window
+ .global::()
+ .set_library_error("No formats selected — tick at least one.".into());
return;
}
@@ -164,8 +174,10 @@ fn open_catalog_soon(
return;
}
- window.set_library_opening(true);
- window.set_library_status("Reading the catalog on this device…".into());
+ window.global::().set_library_opening(true);
+ window
+ .global::()
+ .set_library_status("Reading the catalog on this device…".into());
let rx = spawn_catalog_open(path.clone());
let weak = window.as_weak();
@@ -190,7 +202,7 @@ fn open_catalog_soon(
}
};
stop(&held.catalog_timer);
- w.set_library_opening(false);
+ w.global::().set_library_opening(false);
match got {
CatalogOpen::Opened(cat) => {
@@ -305,7 +317,9 @@ fn begin_scan(
filter.iter().count(),
path.display()
);
- window.set_library_status("Starting…".into());
+ window
+ .global::()
+ .set_library_status("Starting…".into());
let rx = library::spawn_scan(
conn.clone(),
@@ -356,9 +370,10 @@ fn drain_scan(
Err(std::sync::mpsc::TryRecvError::Disconnected) => {
// A worker that died without sending must not leave
// the screen on "Scanning…" forever.
- if w.get_library_scanning() {
- w.set_library_scanning(false);
- w.set_library_error("scan ended unexpectedly".into());
+ if w.global::().get_library_scanning() {
+ w.global::().set_library_scanning(false);
+ w.global::()
+ .set_library_error("scan ended unexpectedly".into());
job.fail("ended unexpectedly");
}
stop(&ctl.scan_timer);
@@ -382,7 +397,7 @@ fn drain_scan(
format!("{directories} folders · {images} images")
};
job.detail(status.clone());
- w.set_library_status(status.into());
+ w.global::().set_library_status(status.into());
}
ScanMessage::Done {
found,
@@ -396,7 +411,7 @@ fn drain_scan(
{pruned} folders unchanged, {judgements} judgements \
taken in) in {elapsed_ms} ms"
);
- w.set_library_scanning(false);
+ w.global::().set_library_scanning(false);
// A completed scan is the strongest possible evidence
// the server is reachable, so it clears offline mode
@@ -450,7 +465,7 @@ fn drain_scan(
status
};
job.finish(status.clone());
- w.set_library_status(status.into());
+ w.global::().set_library_status(status.into());
// Usually already open — `show_catalog_now` opened it
// before this scan started, so the grid has been
@@ -485,7 +500,9 @@ fn drain_scan(
// than the part that was scrolled past.
start_sweep(&w, ctl);
}
- Err(e) => w.set_library_error(format!("opening catalog: {e}").into()),
+ Err(e) => w
+ .global::()
+ .set_library_error(format!("opening catalog: {e}").into()),
}
stop(&ctl.scan_timer);
return;
@@ -496,7 +513,7 @@ fn drain_scan(
lost_root,
} => {
log::warn!("scan failed: {message}");
- w.set_library_scanning(false);
+ w.global::().set_library_scanning(false);
// Recorded as a failure even where it is only the
// connection: the grid's offline banner says the server
// is unreachable, and this says which piece of work
@@ -538,7 +555,7 @@ fn drain_scan(
// for.
open_catalog_for_offline(&w, ctl, &catalog_path, &coll_ctl);
} else {
- w.set_library_error(message.into());
+ w.global::().set_library_error(message.into());
}
stop(&ctl.scan_timer);
return;
@@ -566,9 +583,13 @@ pub(crate) fn start_rescan(
return;
};
- window.set_library_scanning(true);
- window.set_library_error(slint::SharedString::new());
- window.set_library_status("Rescanning…".into());
+ window.global::