Record what the spec got wrong about the model that exists
docs/segmentation.md §4 priced arm B as costing a C dependency under the NDK and treated that as most of the difference between the arms. It is not a cost that has to be paid: `ort`'s `alternative-backend` disables its linking entirely and `ort-tract` supplies the API from tract, which is pure Rust. D13's "largest exception the policy would tolerate" turns out not to be needed, and the answer generalises to the face pipeline — so D13's runtime half is now answered and only its licensing half is open. Three findings contradict §4 outright and are recorded as F4-F6 rather than quietly designed around. There is no ADE20K-trained YOLO, so the shipped vocabulary selects subjects and not stuff — "select the sky" comes from the watershed or from nowhere. It is instance segmentation, so it partitions nothing and two people come back as two instances. And tract cannot parse a dynamic-shape export, which fixes the input at 640 square and makes tiling the only route to more semantic resolution. Arm C ships, but §8's criteria are not what decided it, and saying so matters more than claiming the process worked. §8 asked for a two- interaction margin over arm A on a traced corpus. That comparison was never run: F4 and F5 changed what the arms are, and a model that recognises subjects but has no word for sky cannot be a selection tool alone, while a watershed cannot tell a person from the wall behind them. They stopped being candidates and became complements. What is *not* done is written down as plainly: the 24-image corpus is untraced, so M1-M4 have no numbers and "this feels right" has not become one. M5 is answered on one device only, and region ids now reach the sidecar — so a cross-vendor divergence would mean a mask written on the desktop meaning something else on Android. F3 stands.
This commit is contained in:
@@ -1084,7 +1084,8 @@ Full rationale in [requirements.md §8](requirements.md). Summary:
|
|||||||
| D10 | Single adaptive interface | Decided |
|
| D10 | Single adaptive interface | Decided |
|
||||||
| D11 | Product positioning | Decided |
|
| D11 | Product positioning | Decided |
|
||||||
| D12 | Scope versus pace | **Open** |
|
| D12 | Scope versus pace | **Open** |
|
||||||
| D13 | Face inference runtime and model licensing | **Open** |
|
| D13 | Face inference runtime and model licensing | **Runtime answered**, licensing open |
|
||||||
|
| D14 | Segmentation source for local masking | Decided — arm C (docs/segmentation.md §14) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+13
-1
@@ -1192,7 +1192,19 @@ both a smaller build and a usable one — it needs no develop chain.
|
|||||||
|
|
||||||
Resolving D12 sets D3 and [architecture.md §10](architecture.md)'s Phase 2.
|
Resolving D12 sets D3 and [architecture.md §10](architecture.md)'s Phase 2.
|
||||||
|
|
||||||
### D13 — face inference runtime and model licensing · **OPEN**
|
### D13 — face inference runtime and model licensing · **RUNTIME ANSWERED, LICENSING OPEN**
|
||||||
|
|
||||||
|
> **Updated 2026-08-21.** The runtime half of this decision is settled, and by a route the table
|
||||||
|
> below does not contain. `ort` 2.0's `alternative-backend` feature *disables its linking entirely*
|
||||||
|
> and lets another engine supply the `OrtApi`; `ort-tract` supplies it from `tract`, which is pure
|
||||||
|
> Rust. So the third option's operator coverage comes with the first option's dependency profile —
|
||||||
|
> no C, no NDK problem, no exception to the policy. Measured on a real graph before being relied on:
|
||||||
|
> YOLO26n-seg loads with zero unsupported operators and runs 640×640 in ~470 ms of CPU
|
||||||
|
> (docs/segmentation.md §13). §3.9.1's detector and embedder are different graphs and their coverage
|
||||||
|
> has not been checked, but the *approach* no longer needs a decision.
|
||||||
|
>
|
||||||
|
> **The licensing half is untouched.** The InsightFace weights are still non-commercial and still
|
||||||
|
> unusable here. That remains what S14 has to resolve first.
|
||||||
|
|
||||||
§3.9.1 needs to run two neural networks locally. That collides with two settled positions, and
|
§3.9.1 needs to run two neural networks locally. That collides with two settled positions, and
|
||||||
neither collision is small enough to leave implicit.
|
neither collision is small enough to leave implicit.
|
||||||
|
|||||||
+87
-8
@@ -345,14 +345,93 @@ measurement that can invalidate the region-id representation.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 13. Register entries
|
## 13. Arms B and C, and what §4 got wrong
|
||||||
|
|
||||||
To be added when this is accepted:
|
Built 2026-08-21 on branch `local-adjustments`. `core/dr-segment`, `core/dr-gpu/src/mask.rs`,
|
||||||
|
`core/dr-pipeline/src/mask.rs`, and the develop panel.
|
||||||
|
|
||||||
**S15** — *Region segmentation for local masking:* implement arm A and the shared consumers, trace a
|
**The dependency question dissolved rather than being decided.** §4 and D13 both priced arm B as
|
||||||
24-image corpus, measure M1–M7 across arms. **Resolve the licence question before writing arm B.**
|
costing a C dependency under the Android NDK, and treated that as most of the difference between the
|
||||||
Answers: which segmentation source local masking snaps to, and whether a mask can be stored as region
|
arms. It is not a cost that has to be paid: `ort` 2.0's `alternative-backend` feature disables the
|
||||||
ids at all. Relates to: D13, D14, FR-DEV-3, ARCH §5.4, §6.13.
|
linking entirely and lets another engine supply the `OrtApi`, and `ort-tract` — same authors,
|
||||||
|
MIT/Apache — supplies it from `tract`, which is pure Rust. So arm B runs through `ort`'s API with no
|
||||||
|
C anywhere, and D13's "largest exception the policy would tolerate" turns out not to be needed.
|
||||||
|
|
||||||
**D14** — *Segmentation source for local masking* · **OPEN**. Decided by S15 against the criteria in
|
Measured before committing to it, because tract's operator coverage is the thing that could have
|
||||||
§8. Reopens D13's dependency-policy question if arm C wins.
|
sunk it: **yolo26n-seg loads with zero unsupported operators** and runs 640×640 in ~470 ms on the
|
||||||
|
reference desktop's CPU. Correct masks on the standard `bus.jpg` — one bus and three people, outlines
|
||||||
|
following the subjects.
|
||||||
|
|
||||||
|
Three findings that contradict §4 directly, and all three change the design rather than the schedule.
|
||||||
|
|
||||||
|
**F4 — there is no ADE20K-trained YOLO.** §4's whole argument for arm B was ADE20K's 150 classes and
|
||||||
|
their *stuff* categories: "'that patch of sky' is a class here." Checked 2026-08-21: Ultralytics ships
|
||||||
|
YOLO26-seg trained on **COCO**, whose 80 classes are all *things*, and the one HuggingFace repository
|
||||||
|
claiming a YOLO/ADE20K combination is empty. ADE20K models exist as SegFormer/OneFormer/MaskFormer
|
||||||
|
transformers, not as YOLO.
|
||||||
|
|
||||||
|
So the shipped vocabulary selects **subjects**, not **stuff**. "Select the person" works; "select the
|
||||||
|
sky" does not come from the model at all and must come from the watershed. That is a narrower arm B
|
||||||
|
than §4 assumed, and it *raises* the importance of arm C rather than lowering it — the model can no
|
||||||
|
longer be the whole answer for anything.
|
||||||
|
|
||||||
|
**F5 — it is instance segmentation, not semantic segmentation.** §4 assumed a flat partition with
|
||||||
|
class ids that would "populate `RegionField` directly". YOLO-seg does not partition the image; it
|
||||||
|
finds objects, and most pixels in a landscape belong to no instance. Two consequences, one bad and
|
||||||
|
one better than expected: nothing populates a `RegionField` on its own, and two people come back as
|
||||||
|
*two* instances where a semantic model would have returned one "person" area covering both. For
|
||||||
|
selecting a subject the latter is the behaviour worth having.
|
||||||
|
|
||||||
|
**F6 — tract cannot parse a dynamic-shape export.** It fails shape inference on the neck's `Concat`.
|
||||||
|
The graph therefore ships with its input fixed at 640×640 square, and every image is letterboxed into
|
||||||
|
it. This is the constraint behind the tiling option in `semantic.rs`: with a fixed window, tiling is
|
||||||
|
the *only* route to more semantic resolution, and it costs one inference per tile (≈2.8 s for a 3×2
|
||||||
|
grid over a 1600 px proxy against 470 ms whole-frame). Defaulted off — a photographic subject is
|
||||||
|
usually large in frame, which is the case whole-frame inference handles best — and left implemented
|
||||||
|
so §9's corpus can settle it rather than an argument.
|
||||||
|
|
||||||
|
**Arm C ships, and the §8 criteria were not what decided it.** §8 asked for a two-interaction margin
|
||||||
|
over arm A on the scene subset. That comparison was never run, because F4 and F5 changed what the
|
||||||
|
arms *are*: with a model that recognises subjects and has no word for sky, arm B alone cannot be a
|
||||||
|
selection tool at all (§8's "arm B never ships alone" holds, for a stronger reason than expected),
|
||||||
|
and arm A alone cannot tell a person from the wall behind them. They are complements rather than
|
||||||
|
candidates. Arm C's implementation is `prior.rs`: instance membership re-weights the merge saddles,
|
||||||
|
so region pairs the model believes share an object merge early and pairs straddling its edge merge
|
||||||
|
late. **No boundary moves** — only the order in which boundaries dissolve — which is how the result
|
||||||
|
stays pixel-accurate at every level while its coarse levels become named things.
|
||||||
|
|
||||||
|
**M1–M4 remain unmeasured.** The 24-image corpus of §9 has not been traced, so there are no
|
||||||
|
interaction counts and no boundary-accuracy numbers. What exists is a working feature and the
|
||||||
|
evidence that each piece does what it claims in isolation. The corpus is still the thing that would
|
||||||
|
turn "this feels right" into a number, and it is the largest piece of §11 left undone.
|
||||||
|
|
||||||
|
**M5 is unchanged and still the risk it was.** Run-to-run on one device is identical, asserted by a
|
||||||
|
test. Cross-vendor is untouched. Region ids now reach the sidecar, so if the label field proves
|
||||||
|
non-deterministic across vendors a mask written on the desktop will not mean the same thing on
|
||||||
|
Android — see `MaskSource::Regions::signature`, which detects a *retuned* segmentation but not a
|
||||||
|
differently-rounded one.
|
||||||
|
|
||||||
|
**F3 still stands.** `Segmentation::read_field` still copies the label and gradient buffers to the
|
||||||
|
CPU to build the region graph. It is now behind its own `segment-readback` feature rather than
|
||||||
|
sharing `readback` — this transfer is once per image on a worker, where the one AC-8 forbids is per
|
||||||
|
frame in the render loop — but the accumulation still belongs GPU-side with atomics.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 14. Register entries
|
||||||
|
|
||||||
|
**S15** — *Region segmentation for local masking* · **CLOSED 2026-08-21**. Arms A, B and C built; the
|
||||||
|
shared consumers built; the licence question resolved (§7, D14). The 24-image corpus was not traced,
|
||||||
|
so M1–M4 are unmeasured and M5 is answered only on one device. Answers: local masking snaps to arm C,
|
||||||
|
and a mask is stored as region ids. Relates to: D13, D14, FR-DEV-3, ARCH §5.4, §6.13.
|
||||||
|
|
||||||
|
**D14** — *Segmentation source for local masking* · **DECIDED 2026-08-21**: **arm C**, a watershed
|
||||||
|
hierarchy re-weighted by YOLO26n-seg instance membership, with the model optional and the watershed
|
||||||
|
sufficient without it. Weights ship in-tree under AGPL-3.0, which GPLv3 §13 permits and which makes
|
||||||
|
the combined work effectively AGPL — a deliberate change to DarkRoom's licensing posture, not a
|
||||||
|
dependency detail (`core/dr-segment/models/LICENCE.md`).
|
||||||
|
|
||||||
|
**D13** — *inference runtime* · the dependency half is **answered** for segmentation and the answer
|
||||||
|
generalises: `ort` + `ort-tract` gives ONNX inference in pure Rust, so the face pipeline of §3.9.1
|
||||||
|
needs no C dependency either. The *model licensing* half of D13 is untouched — the InsightFace
|
||||||
|
weights are still non-commercial and still unusable here.
|
||||||
|
|||||||
+41
-41
@@ -9,8 +9,8 @@ Denominators are parsed from [`requirements.md`](requirements.md) at run time, n
|
|||||||
|
|
||||||
| Metric | Value |
|
| Metric | Value |
|
||||||
|---|---|
|
|---|---|
|
||||||
| Source files scanned | 129 |
|
| Source files scanned | 143 |
|
||||||
| TRACES tags found | 319 |
|
| TRACES tags found | 330 |
|
||||||
| Requirements defined | 151 |
|
| Requirements defined | 151 |
|
||||||
| Requirements covered | 83 |
|
| Requirements covered | 83 |
|
||||||
| **Coverage** | **55.0%** (83/151) |
|
| **Coverage** | **55.0%** (83/151) |
|
||||||
@@ -35,87 +35,87 @@ _None._
|
|||||||
|---|---|
|
|---|---|
|
||||||
| 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:93`](../core/dr-sync/src/scan.rs#L93), [`core/dr-types/src/lib.rs:196`](../core/dr-types/src/lib.rs#L196), [`core/dr-types/src/lib.rs:265`](../core/dr-types/src/lib.rs#L265), [`core/dr-types/src/lib.rs:298`](../core/dr-types/src/lib.rs#L298), [`tools/traceability/src/lib.rs:479`](../tools/traceability/src/lib.rs#L479), [`tools/traceability/src/lib.rs:511`](../tools/traceability/src/lib.rs#L511), [`ui/dr-ui/src/activity.rs:1`](../ui/dr-ui/src/activity.rs#L1), [`ui/dr-ui/src/library.rs:1`](../ui/dr-ui/src/library.rs#L1) |
|
| FR-CAT-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:93`](../core/dr-sync/src/scan.rs#L93), [`core/dr-types/src/lib.rs:196`](../core/dr-types/src/lib.rs#L196), [`core/dr-types/src/lib.rs:265`](../core/dr-types/src/lib.rs#L265), [`core/dr-types/src/lib.rs:298`](../core/dr-types/src/lib.rs#L298), [`tools/traceability/src/lib.rs:479`](../tools/traceability/src/lib.rs#L479), [`tools/traceability/src/lib.rs:511`](../tools/traceability/src/lib.rs#L511), [`ui/dr-ui/src/activity.rs:1`](../ui/dr-ui/src/activity.rs#L1), [`ui/dr-ui/src/library.rs:1`](../ui/dr-ui/src/library.rs#L1) |
|
||||||
| FR-CAT-11 | [`ui/dr-ui/src/library.rs:152`](../ui/dr-ui/src/library.rs#L152) |
|
| FR-CAT-11 | [`ui/dr-ui/src/library.rs:152`](../ui/dr-ui/src/library.rs#L152) |
|
||||||
| FR-CAT-12 | [`core/dr-pipeline/src/sidecar.rs:108`](../core/dr-pipeline/src/sidecar.rs#L108) |
|
| FR-CAT-12 | [`core/dr-pipeline/src/sidecar.rs:109`](../core/dr-pipeline/src/sidecar.rs#L109) |
|
||||||
| FR-CAT-15 | [`core/dr-catalog/src/schema.rs:258`](../core/dr-catalog/src/schema.rs#L258), [`core/dr-catalog/src/trash.rs:1`](../core/dr-catalog/src/trash.rs#L1), [`core/dr-sync-nextcloud/src/lib.rs:366`](../core/dr-sync-nextcloud/src/lib.rs#L366), [`core/dr-sync/src/lib.rs:122`](../core/dr-sync/src/lib.rs#L122), [`core/dr-sync/src/scan.rs:426`](../core/dr-sync/src/scan.rs#L426), [`core/dr-sync/src/scan.rs:57`](../core/dr-sync/src/scan.rs#L57), [`core/dr-thumbs/src/lib.rs:376`](../core/dr-thumbs/src/lib.rs#L376), [`ui/dr-ui/src/collections_ui.rs:1035`](../ui/dr-ui/src/collections_ui.rs#L1035), [`ui/dr-ui/src/collections_ui.rs:1671`](../ui/dr-ui/src/collections_ui.rs#L1671), [`ui/dr-ui/src/library.rs:152`](../ui/dr-ui/src/library.rs#L152), [`ui/dr-ui/src/library.rs:169`](../ui/dr-ui/src/library.rs#L169), [`ui/dr-ui/src/library.rs:2512`](../ui/dr-ui/src/library.rs#L2512), [`ui/dr-ui/src/library.rs:2544`](../ui/dr-ui/src/library.rs#L2544), [`ui/dr-ui/src/library_ui.rs:112`](../ui/dr-ui/src/library_ui.rs#L112), [`ui/dr-ui/src/library_ui.rs:607`](../ui/dr-ui/src/library_ui.rs#L607), [`ui/dr-ui/src/trash.rs:1`](../ui/dr-ui/src/trash.rs#L1), [`ui/dr-ui/ui/collections.slint:552`](../ui/dr-ui/ui/collections.slint#L552) |
|
| FR-CAT-15 | [`core/dr-catalog/src/schema.rs:258`](../core/dr-catalog/src/schema.rs#L258), [`core/dr-catalog/src/trash.rs:1`](../core/dr-catalog/src/trash.rs#L1), [`core/dr-sync-nextcloud/src/lib.rs:447`](../core/dr-sync-nextcloud/src/lib.rs#L447), [`core/dr-sync/src/lib.rs:122`](../core/dr-sync/src/lib.rs#L122), [`core/dr-sync/src/scan.rs:426`](../core/dr-sync/src/scan.rs#L426), [`core/dr-sync/src/scan.rs:57`](../core/dr-sync/src/scan.rs#L57), [`core/dr-thumbs/src/lib.rs:376`](../core/dr-thumbs/src/lib.rs#L376), [`ui/dr-ui/src/collections_ui.rs:1087`](../ui/dr-ui/src/collections_ui.rs#L1087), [`ui/dr-ui/src/collections_ui.rs:1762`](../ui/dr-ui/src/collections_ui.rs#L1762), [`ui/dr-ui/src/library.rs:152`](../ui/dr-ui/src/library.rs#L152), [`ui/dr-ui/src/library.rs:169`](../ui/dr-ui/src/library.rs#L169), [`ui/dr-ui/src/library.rs:2576`](../ui/dr-ui/src/library.rs#L2576), [`ui/dr-ui/src/library.rs:2608`](../ui/dr-ui/src/library.rs#L2608), [`ui/dr-ui/src/library_ui.rs:112`](../ui/dr-ui/src/library_ui.rs#L112), [`ui/dr-ui/src/library_ui.rs:616`](../ui/dr-ui/src/library_ui.rs#L616), [`ui/dr-ui/src/trash.rs:1`](../ui/dr-ui/src/trash.rs#L1), [`ui/dr-ui/ui/collections.slint:572`](../ui/dr-ui/ui/collections.slint#L572) |
|
||||||
| FR-CAT-1a | [`core/dr-catalog/src/walk.rs:1`](../core/dr-catalog/src/walk.rs#L1), [`core/dr-types/src/lib.rs:49`](../core/dr-types/src/lib.rs#L49) |
|
| FR-CAT-1a | [`core/dr-catalog/src/walk.rs:1`](../core/dr-catalog/src/walk.rs#L1), [`core/dr-types/src/lib.rs:49`](../core/dr-types/src/lib.rs#L49) |
|
||||||
| 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), [`tools/traceability/src/lib.rs:479`](../tools/traceability/src/lib.rs#L479) |
|
| 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), [`tools/traceability/src/lib.rs:479`](../tools/traceability/src/lib.rs#L479) |
|
||||||
| 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:69`](../core/dr-sync/src/scan.rs#L69), [`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) |
|
| 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:69`](../core/dr-sync/src/scan.rs#L69), [`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) |
|
||||||
| 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), [`ui/dr-ui/src/library.rs:1`](../ui/dr-ui/src/library.rs#L1), [`ui/dr-ui/src/library_ui.rs:1`](../ui/dr-ui/src/library_ui.rs#L1) |
|
| 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), [`ui/dr-ui/src/library.rs:1`](../ui/dr-ui/src/library.rs#L1), [`ui/dr-ui/src/library_ui.rs:1`](../ui/dr-ui/src/library_ui.rs#L1) |
|
||||||
| FR-CAT-5 | [`core/dr-catalog/src/rating.rs:1`](../core/dr-catalog/src/rating.rs#L1), [`core/dr-decode/src/lib.rs:240`](../core/dr-decode/src/lib.rs#L240), [`core/dr-decode/src/lib.rs:307`](../core/dr-decode/src/lib.rs#L307), [`core/dr-pipeline/src/sidecar.rs:125`](../core/dr-pipeline/src/sidecar.rs#L125) |
|
| FR-CAT-5 | [`core/dr-catalog/src/rating.rs:1`](../core/dr-catalog/src/rating.rs#L1), [`core/dr-decode/src/lib.rs:240`](../core/dr-decode/src/lib.rs#L240), [`core/dr-decode/src/lib.rs:307`](../core/dr-decode/src/lib.rs#L307), [`core/dr-pipeline/src/sidecar.rs:126`](../core/dr-pipeline/src/sidecar.rs#L126) |
|
||||||
| FR-CAT-6 | [`core/dr-catalog/src/collections.rs:1`](../core/dr-catalog/src/collections.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-types/src/selector.rs:1`](../core/dr-types/src/selector.rs#L1), [`ui/dr-ui/src/library.rs:179`](../ui/dr-ui/src/library.rs#L179) |
|
| FR-CAT-6 | [`core/dr-catalog/src/collections.rs:1`](../core/dr-catalog/src/collections.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-types/src/selector.rs:1`](../core/dr-types/src/selector.rs#L1), [`ui/dr-ui/src/library.rs:179`](../ui/dr-ui/src/library.rs#L179) |
|
||||||
| FR-CAT-7 | [`core/dr-catalog/src/collections.rs:1`](../core/dr-catalog/src/collections.rs#L1), [`core/dr-catalog/src/merge.rs:1`](../core/dr-catalog/src/merge.rs#L1), [`core/dr-catalog/src/sync.rs:1`](../core/dr-catalog/src/sync.rs#L1), [`core/dr-types/src/selector.rs:1`](../core/dr-types/src/selector.rs#L1), [`ui/dr-ui/src/collections_ui.rs:1408`](../ui/dr-ui/src/collections_ui.rs#L1408), [`ui/dr-ui/src/collections_ui.rs:1`](../ui/dr-ui/src/collections_ui.rs#L1), [`ui/dr-ui/src/derived_sync.rs:1`](../ui/dr-ui/src/derived_sync.rs#L1), [`ui/dr-ui/ui/app.slint:474`](../ui/dr-ui/ui/app.slint#L474), [`ui/dr-ui/ui/collections.slint:4`](../ui/dr-ui/ui/collections.slint#L4), [`ui/dr-ui/ui/library.slint:492`](../ui/dr-ui/ui/library.slint#L492), [`ui/dr-ui/ui/library.slint:511`](../ui/dr-ui/ui/library.slint#L511) |
|
| FR-CAT-7 | [`core/dr-catalog/src/collections.rs:1`](../core/dr-catalog/src/collections.rs#L1), [`core/dr-catalog/src/merge.rs:1`](../core/dr-catalog/src/merge.rs#L1), [`core/dr-catalog/src/sync.rs:1`](../core/dr-catalog/src/sync.rs#L1), [`core/dr-types/src/selector.rs:1`](../core/dr-types/src/selector.rs#L1), [`ui/dr-ui/src/collections_ui.rs:1460`](../ui/dr-ui/src/collections_ui.rs#L1460), [`ui/dr-ui/src/collections_ui.rs:1`](../ui/dr-ui/src/collections_ui.rs#L1), [`ui/dr-ui/src/derived_sync.rs:1`](../ui/dr-ui/src/derived_sync.rs#L1), [`ui/dr-ui/ui/app.slint:492`](../ui/dr-ui/ui/app.slint#L492), [`ui/dr-ui/ui/collections.slint:4`](../ui/dr-ui/ui/collections.slint#L4), [`ui/dr-ui/ui/library.slint:492`](../ui/dr-ui/ui/library.slint#L492), [`ui/dr-ui/ui/library.slint:511`](../ui/dr-ui/ui/library.slint#L511) |
|
||||||
| FR-CAT-8 | [`core/dr-pipeline/src/sidecar.rs:89`](../core/dr-pipeline/src/sidecar.rs#L89), [`ui/dr-ui/src/develop.rs:962`](../ui/dr-ui/src/develop.rs#L962), [`ui/dr-ui/src/export.rs:697`](../ui/dr-ui/src/export.rs#L697), [`ui/dr-ui/src/lib.rs:1044`](../ui/dr-ui/src/lib.rs#L1044), [`ui/dr-ui/src/lib.rs:1377`](../ui/dr-ui/src/lib.rs#L1377), [`ui/dr-ui/src/lib.rs:1482`](../ui/dr-ui/src/lib.rs#L1482), [`ui/dr-ui/src/lib.rs:453`](../ui/dr-ui/src/lib.rs#L453), [`ui/dr-ui/src/lib.rs:727`](../ui/dr-ui/src/lib.rs#L727), [`ui/dr-ui/src/library.rs:1411`](../ui/dr-ui/src/library.rs#L1411), [`ui/dr-ui/src/library.rs:291`](../ui/dr-ui/src/library.rs#L291), [`ui/dr-ui/src/library.rs:349`](../ui/dr-ui/src/library.rs#L349), [`ui/dr-ui/src/library.rs:565`](../ui/dr-ui/src/library.rs#L565), [`ui/dr-ui/src/library_ui.rs:3486`](../ui/dr-ui/src/library_ui.rs#L3486), [`ui/dr-ui/src/sidecar_cache.rs:1`](../ui/dr-ui/src/sidecar_cache.rs#L1) |
|
| FR-CAT-8 | [`core/dr-pipeline/src/sidecar.rs:90`](../core/dr-pipeline/src/sidecar.rs#L90), [`ui/dr-ui/src/develop.rs:1429`](../ui/dr-ui/src/develop.rs#L1429), [`ui/dr-ui/src/export.rs:697`](../ui/dr-ui/src/export.rs#L697), [`ui/dr-ui/src/lib.rs:1051`](../ui/dr-ui/src/lib.rs#L1051), [`ui/dr-ui/src/lib.rs:1384`](../ui/dr-ui/src/lib.rs#L1384), [`ui/dr-ui/src/lib.rs:1489`](../ui/dr-ui/src/lib.rs#L1489), [`ui/dr-ui/src/lib.rs:460`](../ui/dr-ui/src/lib.rs#L460), [`ui/dr-ui/src/lib.rs:734`](../ui/dr-ui/src/lib.rs#L734), [`ui/dr-ui/src/library.rs:1475`](../ui/dr-ui/src/library.rs#L1475), [`ui/dr-ui/src/library.rs:340`](../ui/dr-ui/src/library.rs#L340), [`ui/dr-ui/src/library.rs:398`](../ui/dr-ui/src/library.rs#L398), [`ui/dr-ui/src/library.rs:626`](../ui/dr-ui/src/library.rs#L626), [`ui/dr-ui/src/library_ui.rs:3496`](../ui/dr-ui/src/library_ui.rs#L3496), [`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:230`](../core/dr-catalog/src/schema.rs#L230), [`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:704`](../core/dr-catalog/src/walk.rs#L704), [`core/dr-sync-nextcloud/src/desktop_client.rs:30`](../core/dr-sync-nextcloud/src/desktop_client.rs#L30), [`core/dr-sync/src/reachability.rs:1`](../core/dr-sync/src/reachability.rs#L1), [`core/dr-types/src/lib.rs:115`](../core/dr-types/src/lib.rs#L115), [`ui/dr-ui/src/library.rs:1371`](../ui/dr-ui/src/library.rs#L1371), [`ui/dr-ui/src/library.rs:138`](../ui/dr-ui/src/library.rs#L138), [`ui/dr-ui/src/library.rs:1448`](../ui/dr-ui/src/library.rs#L1448), [`ui/dr-ui/src/library.rs:196`](../ui/dr-ui/src/library.rs#L196), [`ui/dr-ui/src/library.rs:2632`](../ui/dr-ui/src/library.rs#L2632), [`ui/dr-ui/src/library.rs:349`](../ui/dr-ui/src/library.rs#L349), [`ui/dr-ui/src/library.rs:549`](../ui/dr-ui/src/library.rs#L549), [`ui/dr-ui/src/library.rs:565`](../ui/dr-ui/src/library.rs#L565), [`ui/dr-ui/src/library.rs:619`](../ui/dr-ui/src/library.rs#L619), [`ui/dr-ui/src/library_ui.rs:1391`](../ui/dr-ui/src/library_ui.rs#L1391), [`ui/dr-ui/src/library_ui.rs:1417`](../ui/dr-ui/src/library_ui.rs#L1417), [`ui/dr-ui/src/library_ui.rs:1433`](../ui/dr-ui/src/library_ui.rs#L1433), [`ui/dr-ui/src/library_ui.rs:146`](../ui/dr-ui/src/library_ui.rs#L146), [`ui/dr-ui/src/library_ui.rs:1527`](../ui/dr-ui/src/library_ui.rs#L1527), [`ui/dr-ui/src/library_ui.rs:1789`](../ui/dr-ui/src/library_ui.rs#L1789), [`ui/dr-ui/src/library_ui.rs:179`](../ui/dr-ui/src/library_ui.rs#L179), [`ui/dr-ui/src/library_ui.rs:2054`](../ui/dr-ui/src/library_ui.rs#L2054), [`ui/dr-ui/src/library_ui.rs:2388`](../ui/dr-ui/src/library_ui.rs#L2388), [`ui/dr-ui/src/library_ui.rs:2460`](../ui/dr-ui/src/library_ui.rs#L2460), [`ui/dr-ui/src/library_ui.rs:2625`](../ui/dr-ui/src/library_ui.rs#L2625), [`ui/dr-ui/src/library_ui.rs:322`](../ui/dr-ui/src/library_ui.rs#L322), [`ui/dr-ui/src/library_ui.rs:3638`](../ui/dr-ui/src/library_ui.rs#L3638), [`ui/dr-ui/src/library_ui.rs:3748`](../ui/dr-ui/src/library_ui.rs#L3748), [`ui/dr-ui/src/library_ui.rs:380`](../ui/dr-ui/src/library_ui.rs#L380), [`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:230`](../core/dr-catalog/src/schema.rs#L230), [`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:704`](../core/dr-catalog/src/walk.rs#L704), [`core/dr-sync-nextcloud/src/desktop_client.rs:30`](../core/dr-sync-nextcloud/src/desktop_client.rs#L30), [`core/dr-sync/src/reachability.rs:1`](../core/dr-sync/src/reachability.rs#L1), [`core/dr-types/src/lib.rs:115`](../core/dr-types/src/lib.rs#L115), [`ui/dr-ui/src/library.rs:138`](../ui/dr-ui/src/library.rs#L138), [`ui/dr-ui/src/library.rs:1435`](../ui/dr-ui/src/library.rs#L1435), [`ui/dr-ui/src/library.rs:1512`](../ui/dr-ui/src/library.rs#L1512), [`ui/dr-ui/src/library.rs:196`](../ui/dr-ui/src/library.rs#L196), [`ui/dr-ui/src/library.rs:2791`](../ui/dr-ui/src/library.rs#L2791), [`ui/dr-ui/src/library.rs:398`](../ui/dr-ui/src/library.rs#L398), [`ui/dr-ui/src/library.rs:610`](../ui/dr-ui/src/library.rs#L610), [`ui/dr-ui/src/library.rs:626`](../ui/dr-ui/src/library.rs#L626), [`ui/dr-ui/src/library.rs:680`](../ui/dr-ui/src/library.rs#L680), [`ui/dr-ui/src/library_ui.rs:1400`](../ui/dr-ui/src/library_ui.rs#L1400), [`ui/dr-ui/src/library_ui.rs:1426`](../ui/dr-ui/src/library_ui.rs#L1426), [`ui/dr-ui/src/library_ui.rs:1442`](../ui/dr-ui/src/library_ui.rs#L1442), [`ui/dr-ui/src/library_ui.rs:1536`](../ui/dr-ui/src/library_ui.rs#L1536), [`ui/dr-ui/src/library_ui.rs:154`](../ui/dr-ui/src/library_ui.rs#L154), [`ui/dr-ui/src/library_ui.rs:1806`](../ui/dr-ui/src/library_ui.rs#L1806), [`ui/dr-ui/src/library_ui.rs:187`](../ui/dr-ui/src/library_ui.rs#L187), [`ui/dr-ui/src/library_ui.rs:2071`](../ui/dr-ui/src/library_ui.rs#L2071), [`ui/dr-ui/src/library_ui.rs:2405`](../ui/dr-ui/src/library_ui.rs#L2405), [`ui/dr-ui/src/library_ui.rs:2477`](../ui/dr-ui/src/library_ui.rs#L2477), [`ui/dr-ui/src/library_ui.rs:2642`](../ui/dr-ui/src/library_ui.rs#L2642), [`ui/dr-ui/src/library_ui.rs:331`](../ui/dr-ui/src/library_ui.rs#L331), [`ui/dr-ui/src/library_ui.rs:3692`](../ui/dr-ui/src/library_ui.rs#L3692), [`ui/dr-ui/src/library_ui.rs:3807`](../ui/dr-ui/src/library_ui.rs#L3807), [`ui/dr-ui/src/library_ui.rs:389`](../ui/dr-ui/src/library_ui.rs#L389), [`ui/dr-ui/src/sidecar_cache.rs:1`](../ui/dr-ui/src/sidecar_cache.rs#L1) |
|
||||||
| FR-CULL-1 | [`core/dr-decode/src/preview.rs:134`](../core/dr-decode/src/preview.rs#L134) |
|
| FR-CULL-1 | [`core/dr-decode/src/preview.rs:134`](../core/dr-decode/src/preview.rs#L134) |
|
||||||
| FR-CULL-2 | [`core/dr-decode/src/locate.rs:1`](../core/dr-decode/src/locate.rs#L1), [`core/dr-decode/src/preview.rs:161`](../core/dr-decode/src/preview.rs#L161) |
|
| FR-CULL-2 | [`core/dr-decode/src/locate.rs:1`](../core/dr-decode/src/locate.rs#L1), [`core/dr-decode/src/preview.rs:161`](../core/dr-decode/src/preview.rs#L161) |
|
||||||
| FR-CULL-4 | [`core/dr-catalog/src/rating.rs:1`](../core/dr-catalog/src/rating.rs#L1), [`core/dr-pipeline/src/sidecar.rs:125`](../core/dr-pipeline/src/sidecar.rs#L125), [`ui/dr-ui/src/library.rs:179`](../ui/dr-ui/src/library.rs#L179), [`ui/dr-ui/src/library.rs:291`](../ui/dr-ui/src/library.rs#L291) |
|
| FR-CULL-4 | [`core/dr-catalog/src/rating.rs:1`](../core/dr-catalog/src/rating.rs#L1), [`core/dr-pipeline/src/sidecar.rs:126`](../core/dr-pipeline/src/sidecar.rs#L126), [`ui/dr-ui/src/library.rs:179`](../ui/dr-ui/src/library.rs#L179), [`ui/dr-ui/src/library.rs:340`](../ui/dr-ui/src/library.rs#L340) |
|
||||||
| FR-DEV-3 | [`core/dr-pipeline/src/framing.rs:185`](../core/dr-pipeline/src/framing.rs#L185) |
|
| FR-DEV-3 | [`core/dr-gpu/src/adjust.rs:1388`](../core/dr-gpu/src/adjust.rs#L1388), [`core/dr-gpu/src/adjust.rs:297`](../core/dr-gpu/src/adjust.rs#L297), [`core/dr-pipeline/src/framing.rs:185`](../core/dr-pipeline/src/framing.rs#L185), [`core/dr-pipeline/src/operation.rs:196`](../core/dr-pipeline/src/operation.rs#L196), [`core/dr-pipeline/src/sidecar.rs:147`](../core/dr-pipeline/src/sidecar.rs#L147), [`ui/dr-ui/src/develop.rs:49`](../ui/dr-ui/src/develop.rs#L49), [`ui/dr-ui/src/develop.rs:621`](../ui/dr-ui/src/develop.rs#L621), [`ui/dr-ui/src/develop.rs:732`](../ui/dr-ui/src/develop.rs#L732), [`ui/dr-ui/src/lib.rs:1732`](../ui/dr-ui/src/lib.rs#L1732), [`ui/dr-ui/src/lib.rs:286`](../ui/dr-ui/src/lib.rs#L286) |
|
||||||
| FR-DEV-3a | [`core/dr-pipeline/build.rs:1734`](../core/dr-pipeline/build.rs#L1734), [`core/dr-pipeline/ops/exposure.yaml:1`](../core/dr-pipeline/ops/exposure.yaml#L1), [`core/dr-pipeline/src/descriptor.rs:117`](../core/dr-pipeline/src/descriptor.rs#L117), [`core/dr-pipeline/src/descriptor.rs:157`](../core/dr-pipeline/src/descriptor.rs#L157), [`core/dr-pipeline/src/descriptor.rs:177`](../core/dr-pipeline/src/descriptor.rs#L177), [`core/dr-pipeline/src/descriptor.rs:232`](../core/dr-pipeline/src/descriptor.rs#L232), [`core/dr-pipeline/src/framing.rs:256`](../core/dr-pipeline/src/framing.rs#L256), [`core/dr-pipeline/src/graph.rs:133`](../core/dr-pipeline/src/graph.rs#L133), [`core/dr-pipeline/src/graph.rs:17`](../core/dr-pipeline/src/graph.rs#L17), [`core/dr-pipeline/src/graph.rs:41`](../core/dr-pipeline/src/graph.rs#L41), [`core/dr-pipeline/src/operation.rs:106`](../core/dr-pipeline/src/operation.rs#L106) |
|
| FR-DEV-3a | [`core/dr-pipeline/build.rs:1734`](../core/dr-pipeline/build.rs#L1734), [`core/dr-pipeline/ops/exposure.yaml:1`](../core/dr-pipeline/ops/exposure.yaml#L1), [`core/dr-pipeline/src/descriptor.rs:117`](../core/dr-pipeline/src/descriptor.rs#L117), [`core/dr-pipeline/src/descriptor.rs:157`](../core/dr-pipeline/src/descriptor.rs#L157), [`core/dr-pipeline/src/descriptor.rs:177`](../core/dr-pipeline/src/descriptor.rs#L177), [`core/dr-pipeline/src/descriptor.rs:232`](../core/dr-pipeline/src/descriptor.rs#L232), [`core/dr-pipeline/src/framing.rs:256`](../core/dr-pipeline/src/framing.rs#L256), [`core/dr-pipeline/src/graph.rs:151`](../core/dr-pipeline/src/graph.rs#L151), [`core/dr-pipeline/src/graph.rs:18`](../core/dr-pipeline/src/graph.rs#L18), [`core/dr-pipeline/src/graph.rs:42`](../core/dr-pipeline/src/graph.rs#L42), [`core/dr-pipeline/src/mask.rs:237`](../core/dr-pipeline/src/mask.rs#L237), [`core/dr-pipeline/src/operation.rs:107`](../core/dr-pipeline/src/operation.rs#L107) |
|
||||||
| FR-DEV-3b | [`core/dr-pipeline/src/descriptor.rs:177`](../core/dr-pipeline/src/descriptor.rs#L177), [`core/dr-pipeline/src/framing.rs:256`](../core/dr-pipeline/src/framing.rs#L256), [`core/dr-pipeline/src/graph.rs:41`](../core/dr-pipeline/src/graph.rs#L41), [`core/dr-pipeline/src/operation.rs:106`](../core/dr-pipeline/src/operation.rs#L106) |
|
| FR-DEV-3b | [`core/dr-pipeline/src/descriptor.rs:177`](../core/dr-pipeline/src/descriptor.rs#L177), [`core/dr-pipeline/src/framing.rs:256`](../core/dr-pipeline/src/framing.rs#L256), [`core/dr-pipeline/src/graph.rs:42`](../core/dr-pipeline/src/graph.rs#L42), [`core/dr-pipeline/src/operation.rs:107`](../core/dr-pipeline/src/operation.rs#L107) |
|
||||||
| FR-DEV-3c | [`core/dr-pipeline/build.rs:1734`](../core/dr-pipeline/build.rs#L1734), [`core/dr-pipeline/ops/exposure.yaml:1`](../core/dr-pipeline/ops/exposure.yaml#L1), [`core/dr-pipeline/src/graph.rs:133`](../core/dr-pipeline/src/graph.rs#L133), [`ui/dr-ui/src/develop.rs:1654`](../ui/dr-ui/src/develop.rs#L1654) |
|
| FR-DEV-3c | [`core/dr-pipeline/build.rs:1734`](../core/dr-pipeline/build.rs#L1734), [`core/dr-pipeline/ops/exposure.yaml:1`](../core/dr-pipeline/ops/exposure.yaml#L1), [`core/dr-pipeline/src/graph.rs:151`](../core/dr-pipeline/src/graph.rs#L151), [`core/dr-pipeline/src/mask.rs:237`](../core/dr-pipeline/src/mask.rs#L237), [`ui/dr-ui/src/develop.rs:2121`](../ui/dr-ui/src/develop.rs#L2121) |
|
||||||
| FR-DEV-3d | [`core/dr-pipeline/src/framing.rs:185`](../core/dr-pipeline/src/framing.rs#L185) |
|
| FR-DEV-3d | [`core/dr-pipeline/src/framing.rs:185`](../core/dr-pipeline/src/framing.rs#L185) |
|
||||||
| FR-DEV-3e | [`core/dr-decode/src/lib.rs:492`](../core/dr-decode/src/lib.rs#L492), [`core/dr-decode/src/lib.rs:612`](../core/dr-decode/src/lib.rs#L612) |
|
| FR-DEV-3e | [`core/dr-decode/src/lib.rs:501`](../core/dr-decode/src/lib.rs#L501), [`core/dr-decode/src/lib.rs:643`](../core/dr-decode/src/lib.rs#L643), [`core/dr-decode/src/lib.rs:683`](../core/dr-decode/src/lib.rs#L683) |
|
||||||
| FR-DEV-3h | [`core/dr-decode/src/lib.rs:307`](../core/dr-decode/src/lib.rs#L307), [`core/dr-decode/src/preview.rs:29`](../core/dr-decode/src/preview.rs#L29), [`core/dr-pipeline/src/framing.rs:199`](../core/dr-pipeline/src/framing.rs#L199), [`core/dr-types/src/lib.rs:332`](../core/dr-types/src/lib.rs#L332) |
|
| FR-DEV-3h | [`core/dr-decode/src/lib.rs:307`](../core/dr-decode/src/lib.rs#L307), [`core/dr-decode/src/preview.rs:29`](../core/dr-decode/src/preview.rs#L29), [`core/dr-pipeline/src/framing.rs:199`](../core/dr-pipeline/src/framing.rs#L199), [`core/dr-types/src/lib.rs:332`](../core/dr-types/src/lib.rs#L332) |
|
||||||
| FR-DEV-4 | [`core/dr-gpu/src/lib.rs:210`](../core/dr-gpu/src/lib.rs#L210) |
|
| FR-DEV-4 | [`core/dr-gpu/src/lib.rs:211`](../core/dr-gpu/src/lib.rs#L211) |
|
||||||
| FR-DEV-5 | [`core/dr-pipeline/src/history.rs:124`](../core/dr-pipeline/src/history.rs#L124), [`core/dr-pipeline/src/history.rs:1`](../core/dr-pipeline/src/history.rs#L1), [`core/dr-pipeline/src/history.rs:55`](../core/dr-pipeline/src/history.rs#L55), [`core/dr-pipeline/src/history.rs:71`](../core/dr-pipeline/src/history.rs#L71), [`core/dr-pipeline/src/history.rs:79`](../core/dr-pipeline/src/history.rs#L79), [`ui/dr-ui/src/develop.rs:26`](../ui/dr-ui/src/develop.rs#L26), [`ui/dr-ui/src/develop.rs:978`](../ui/dr-ui/src/develop.rs#L978), [`ui/dr-ui/src/develop.rs:988`](../ui/dr-ui/src/develop.rs#L988), [`ui/dr-ui/src/lib.rs:1072`](../ui/dr-ui/src/lib.rs#L1072) |
|
| FR-DEV-5 | [`core/dr-pipeline/src/history.rs:124`](../core/dr-pipeline/src/history.rs#L124), [`core/dr-pipeline/src/history.rs:1`](../core/dr-pipeline/src/history.rs#L1), [`core/dr-pipeline/src/history.rs:55`](../core/dr-pipeline/src/history.rs#L55), [`core/dr-pipeline/src/history.rs:71`](../core/dr-pipeline/src/history.rs#L71), [`core/dr-pipeline/src/history.rs:79`](../core/dr-pipeline/src/history.rs#L79), [`ui/dr-ui/src/develop.rs:1445`](../ui/dr-ui/src/develop.rs#L1445), [`ui/dr-ui/src/develop.rs:1455`](../ui/dr-ui/src/develop.rs#L1455), [`ui/dr-ui/src/develop.rs:31`](../ui/dr-ui/src/develop.rs#L31), [`ui/dr-ui/src/lib.rs:1079`](../ui/dr-ui/src/lib.rs#L1079) |
|
||||||
| FR-DEV-6 | [`core/dr-pipeline/src/preset.rs:1`](../core/dr-pipeline/src/preset.rs#L1), [`core/dr-types/src/settings.rs:61`](../core/dr-types/src/settings.rs#L61), [`ui/dr-ui/src/develop.rs:939`](../ui/dr-ui/src/develop.rs#L939), [`ui/dr-ui/src/develop.rs:949`](../ui/dr-ui/src/develop.rs#L949), [`ui/dr-ui/src/lib.rs:1044`](../ui/dr-ui/src/lib.rs#L1044), [`ui/dr-ui/src/library.rs:1411`](../ui/dr-ui/src/library.rs#L1411), [`ui/dr-ui/src/library.rs:291`](../ui/dr-ui/src/library.rs#L291), [`ui/dr-ui/src/library.rs:319`](../ui/dr-ui/src/library.rs#L319), [`ui/dr-ui/src/library_ui.rs:1885`](../ui/dr-ui/src/library_ui.rs#L1885), [`ui/dr-ui/src/library_ui.rs:348`](../ui/dr-ui/src/library_ui.rs#L348), [`ui/dr-ui/src/presets.rs:1`](../ui/dr-ui/src/presets.rs#L1), [`ui/dr-ui/src/settings_ui.rs:506`](../ui/dr-ui/src/settings_ui.rs#L506), [`ui/dr-ui/ui/adjust.slint:569`](../ui/dr-ui/ui/adjust.slint#L569), [`ui/dr-ui/ui/library.slint:464`](../ui/dr-ui/ui/library.slint#L464), [`ui/dr-ui/ui/library.slint:521`](../ui/dr-ui/ui/library.slint#L521), [`ui/dr-ui/ui/library.slint:853`](../ui/dr-ui/ui/library.slint#L853), [`ui/dr-ui/ui/settings.slint:79`](../ui/dr-ui/ui/settings.slint#L79) |
|
| FR-DEV-6 | [`core/dr-pipeline/src/preset.rs:1`](../core/dr-pipeline/src/preset.rs#L1), [`core/dr-types/src/settings.rs:61`](../core/dr-types/src/settings.rs#L61), [`ui/dr-ui/src/develop.rs:1406`](../ui/dr-ui/src/develop.rs#L1406), [`ui/dr-ui/src/develop.rs:1416`](../ui/dr-ui/src/develop.rs#L1416), [`ui/dr-ui/src/lib.rs:1051`](../ui/dr-ui/src/lib.rs#L1051), [`ui/dr-ui/src/library.rs:1475`](../ui/dr-ui/src/library.rs#L1475), [`ui/dr-ui/src/library.rs:340`](../ui/dr-ui/src/library.rs#L340), [`ui/dr-ui/src/library.rs:368`](../ui/dr-ui/src/library.rs#L368), [`ui/dr-ui/src/library_ui.rs:1902`](../ui/dr-ui/src/library_ui.rs#L1902), [`ui/dr-ui/src/library_ui.rs:357`](../ui/dr-ui/src/library_ui.rs#L357), [`ui/dr-ui/src/presets.rs:1`](../ui/dr-ui/src/presets.rs#L1), [`ui/dr-ui/src/settings_ui.rs:506`](../ui/dr-ui/src/settings_ui.rs#L506), [`ui/dr-ui/ui/adjust.slint:569`](../ui/dr-ui/ui/adjust.slint#L569), [`ui/dr-ui/ui/library.slint:464`](../ui/dr-ui/ui/library.slint#L464), [`ui/dr-ui/ui/library.slint:521`](../ui/dr-ui/ui/library.slint#L521), [`ui/dr-ui/ui/library.slint:856`](../ui/dr-ui/ui/library.slint#L856), [`ui/dr-ui/ui/settings.slint:79`](../ui/dr-ui/ui/settings.slint#L79) |
|
||||||
| FR-DSP-1 | [`core/dr-gpu/src/adjust.rs:1135`](../core/dr-gpu/src/adjust.rs#L1135), [`core/dr-gpu/src/adjust.rs:1168`](../core/dr-gpu/src/adjust.rs#L1168), [`core/dr-gpu/src/adjust.rs:42`](../core/dr-gpu/src/adjust.rs#L42), [`core/dr-gpu/src/lib.rs:47`](../core/dr-gpu/src/lib.rs#L47), [`core/dr-gpu/src/lib.rs:87`](../core/dr-gpu/src/lib.rs#L87), [`ui/dr-ui/src/develop.rs:1126`](../ui/dr-ui/src/develop.rs#L1126), [`ui/dr-ui/src/develop.rs:1200`](../ui/dr-ui/src/develop.rs#L1200), [`ui/dr-ui/src/develop.rs:1234`](../ui/dr-ui/src/develop.rs#L1234), [`ui/dr-ui/src/develop.rs:532`](../ui/dr-ui/src/develop.rs#L532), [`ui/dr-ui/src/lib.rs:54`](../ui/dr-ui/src/lib.rs#L54), [`ui/dr-ui/src/lib.rs:626`](../ui/dr-ui/src/lib.rs#L626) |
|
| FR-DSP-1 | [`core/dr-gpu/src/adjust.rs:1311`](../core/dr-gpu/src/adjust.rs#L1311), [`core/dr-gpu/src/adjust.rs:1388`](../core/dr-gpu/src/adjust.rs#L1388), [`core/dr-gpu/src/adjust.rs:1473`](../core/dr-gpu/src/adjust.rs#L1473), [`core/dr-gpu/src/adjust.rs:42`](../core/dr-gpu/src/adjust.rs#L42), [`core/dr-gpu/src/lib.rs:48`](../core/dr-gpu/src/lib.rs#L48), [`core/dr-gpu/src/lib.rs:88`](../core/dr-gpu/src/lib.rs#L88), [`ui/dr-ui/src/develop.rs:1593`](../ui/dr-ui/src/develop.rs#L1593), [`ui/dr-ui/src/develop.rs:1667`](../ui/dr-ui/src/develop.rs#L1667), [`ui/dr-ui/src/develop.rs:1701`](../ui/dr-ui/src/develop.rs#L1701), [`ui/dr-ui/src/develop.rs:992`](../ui/dr-ui/src/develop.rs#L992), [`ui/dr-ui/src/lib.rs:56`](../ui/dr-ui/src/lib.rs#L56), [`ui/dr-ui/src/lib.rs:633`](../ui/dr-ui/src/lib.rs#L633) |
|
||||||
| FR-DSP-6 | [`core/dr-pipeline/src/operation.rs:168`](../core/dr-pipeline/src/operation.rs#L168), [`core/dr-types/src/colour.rs:1`](../core/dr-types/src/colour.rs#L1) |
|
| FR-DSP-6 | [`core/dr-pipeline/src/operation.rs:169`](../core/dr-pipeline/src/operation.rs#L169), [`core/dr-types/src/colour.rs:1`](../core/dr-types/src/colour.rs#L1) |
|
||||||
| FR-DSP-7 | [`core/dr-gpu/src/histogram.rs:147`](../core/dr-gpu/src/histogram.rs#L147), [`core/dr-gpu/src/histogram.rs:1`](../core/dr-gpu/src/histogram.rs#L1), [`core/dr-gpu/src/histogram.rs:281`](../core/dr-gpu/src/histogram.rs#L281), [`core/dr-gpu/src/histogram.rs:50`](../core/dr-gpu/src/histogram.rs#L50), [`core/dr-gpu/src/shaders/histogram.wgsl:1`](../core/dr-gpu/src/shaders/histogram.wgsl#L1), [`ui/dr-ui/src/develop.rs:2157`](../ui/dr-ui/src/develop.rs#L2157), [`ui/dr-ui/src/develop.rs:2189`](../ui/dr-ui/src/develop.rs#L2189), [`ui/dr-ui/src/develop.rs:37`](../ui/dr-ui/src/develop.rs#L37), [`ui/dr-ui/src/develop.rs:576`](../ui/dr-ui/src/develop.rs#L576), [`ui/dr-ui/src/histogram.rs:1`](../ui/dr-ui/src/histogram.rs#L1), [`ui/dr-ui/src/lib.rs:1124`](../ui/dr-ui/src/lib.rs#L1124), [`ui/dr-ui/src/lib.rs:279`](../ui/dr-ui/src/lib.rs#L279), [`ui/dr-ui/ui/app.slint:227`](../ui/dr-ui/ui/app.slint#L227), [`ui/dr-ui/ui/histogram.slint:122`](../ui/dr-ui/ui/histogram.slint#L122), [`ui/dr-ui/ui/histogram.slint:1`](../ui/dr-ui/ui/histogram.slint#L1) |
|
| FR-DSP-7 | [`core/dr-gpu/src/histogram.rs:147`](../core/dr-gpu/src/histogram.rs#L147), [`core/dr-gpu/src/histogram.rs:1`](../core/dr-gpu/src/histogram.rs#L1), [`core/dr-gpu/src/histogram.rs:281`](../core/dr-gpu/src/histogram.rs#L281), [`core/dr-gpu/src/histogram.rs:50`](../core/dr-gpu/src/histogram.rs#L50), [`core/dr-gpu/src/shaders/histogram.wgsl:1`](../core/dr-gpu/src/shaders/histogram.wgsl#L1), [`ui/dr-ui/src/develop.rs:1043`](../ui/dr-ui/src/develop.rs#L1043), [`ui/dr-ui/src/develop.rs:2624`](../ui/dr-ui/src/develop.rs#L2624), [`ui/dr-ui/src/develop.rs:2656`](../ui/dr-ui/src/develop.rs#L2656), [`ui/dr-ui/src/develop.rs:42`](../ui/dr-ui/src/develop.rs#L42), [`ui/dr-ui/src/histogram.rs:1`](../ui/dr-ui/src/histogram.rs#L1), [`ui/dr-ui/src/lib.rs:1131`](../ui/dr-ui/src/lib.rs#L1131), [`ui/dr-ui/src/lib.rs:281`](../ui/dr-ui/src/lib.rs#L281), [`ui/dr-ui/ui/app.slint:242`](../ui/dr-ui/ui/app.slint#L242), [`ui/dr-ui/ui/histogram.slint:122`](../ui/dr-ui/ui/histogram.slint#L122), [`ui/dr-ui/ui/histogram.slint:1`](../ui/dr-ui/ui/histogram.slint#L1) |
|
||||||
| 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-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:137`](../core/dr-export/src/lib.rs#L137), [`core/dr-export/src/lib.rs:1`](../core/dr-export/src/lib.rs#L1), [`core/dr-export/src/lib.rs:50`](../core/dr-export/src/lib.rs#L50), [`core/dr-gpu/src/adjust.rs:1316`](../core/dr-gpu/src/adjust.rs#L1316), [`core/dr-pipeline/src/graph.rs:298`](../core/dr-pipeline/src/graph.rs#L298), [`core/dr-pipeline/src/operation.rs:168`](../core/dr-pipeline/src/operation.rs#L168), [`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:454`](../core/dr-types/src/settings.rs#L454), [`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:137`](../core/dr-export/src/lib.rs#L137), [`core/dr-export/src/lib.rs:1`](../core/dr-export/src/lib.rs#L1), [`core/dr-export/src/lib.rs:50`](../core/dr-export/src/lib.rs#L50), [`core/dr-gpu/src/adjust.rs:1621`](../core/dr-gpu/src/adjust.rs#L1621), [`core/dr-pipeline/src/graph.rs:322`](../core/dr-pipeline/src/graph.rs#L322), [`core/dr-pipeline/src/operation.rs:169`](../core/dr-pipeline/src/operation.rs#L169), [`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:454`](../core/dr-types/src/settings.rs#L454), [`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:1`](../core/dr-export/src/lib.rs#L1), [`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-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-3 | [`core/dr-export/src/lib.rs:1`](../core/dr-export/src/lib.rs#L1), [`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-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-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-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-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:317`](../ui/dr-ui/src/lib.rs#L317), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1), [`ui/dr-ui/src/settings_ui.rs:48`](../ui/dr-ui/src/settings_ui.rs#L48), [`ui/dr-ui/src/settings_ui.rs:561`](../ui/dr-ui/src/settings_ui.rs#L561) |
|
| 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:324`](../ui/dr-ui/src/lib.rs#L324), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1), [`ui/dr-ui/src/settings_ui.rs:48`](../ui/dr-ui/src/settings_ui.rs#L48), [`ui/dr-ui/src/settings_ui.rs:561`](../ui/dr-ui/src/settings_ui.rs#L561) |
|
||||||
| FR-EXP-7 | [`ui/dr-ui/src/activity.rs:83`](../ui/dr-ui/src/activity.rs#L83), [`ui/dr-ui/src/export.rs:1`](../ui/dr-ui/src/export.rs#L1), [`ui/dr-ui/src/export.rs:879`](../ui/dr-ui/src/export.rs#L879), [`ui/dr-ui/src/lib.rs:1648`](../ui/dr-ui/src/lib.rs#L1648), [`ui/dr-ui/src/lib.rs:170`](../ui/dr-ui/src/lib.rs#L170), [`ui/dr-ui/src/lib.rs:317`](../ui/dr-ui/src/lib.rs#L317), [`ui/dr-ui/src/lib.rs:352`](../ui/dr-ui/src/lib.rs#L352), [`ui/dr-ui/src/lib.rs:379`](../ui/dr-ui/src/lib.rs#L379), [`ui/dr-ui/src/library_ui.rs:2477`](../ui/dr-ui/src/library_ui.rs#L2477), [`ui/dr-ui/src/library_ui.rs:4186`](../ui/dr-ui/src/library_ui.rs#L4186), [`ui/dr-ui/src/library_ui.rs:4198`](../ui/dr-ui/src/library_ui.rs#L4198), [`ui/dr-ui/src/library_ui.rs:4210`](../ui/dr-ui/src/library_ui.rs#L4210), [`ui/dr-ui/src/library_ui.rs:439`](../ui/dr-ui/src/library_ui.rs#L439), [`ui/dr-ui/src/library_ui.rs:510`](../ui/dr-ui/src/library_ui.rs#L510), [`ui/dr-ui/src/library_ui.rs:567`](../ui/dr-ui/src/library_ui.rs#L567), [`ui/dr-ui/ui/app.slint:1021`](../ui/dr-ui/ui/app.slint#L1021), [`ui/dr-ui/ui/app.slint:713`](../ui/dr-ui/ui/app.slint#L713), [`ui/dr-ui/ui/library.slint:468`](../ui/dr-ui/ui/library.slint#L468), [`ui/dr-ui/ui/library.slint:536`](../ui/dr-ui/ui/library.slint#L536), [`ui/dr-ui/ui/library.slint:861`](../ui/dr-ui/ui/library.slint#L861) |
|
| FR-EXP-7 | [`ui/dr-ui/src/activity.rs:83`](../ui/dr-ui/src/activity.rs#L83), [`ui/dr-ui/src/export.rs:1`](../ui/dr-ui/src/export.rs#L1), [`ui/dr-ui/src/export.rs:879`](../ui/dr-ui/src/export.rs#L879), [`ui/dr-ui/src/lib.rs:1655`](../ui/dr-ui/src/lib.rs#L1655), [`ui/dr-ui/src/lib.rs:172`](../ui/dr-ui/src/lib.rs#L172), [`ui/dr-ui/src/lib.rs:324`](../ui/dr-ui/src/lib.rs#L324), [`ui/dr-ui/src/lib.rs:359`](../ui/dr-ui/src/lib.rs#L359), [`ui/dr-ui/src/lib.rs:386`](../ui/dr-ui/src/lib.rs#L386), [`ui/dr-ui/src/library_ui.rs:2494`](../ui/dr-ui/src/library_ui.rs#L2494), [`ui/dr-ui/src/library_ui.rs:4245`](../ui/dr-ui/src/library_ui.rs#L4245), [`ui/dr-ui/src/library_ui.rs:4257`](../ui/dr-ui/src/library_ui.rs#L4257), [`ui/dr-ui/src/library_ui.rs:4269`](../ui/dr-ui/src/library_ui.rs#L4269), [`ui/dr-ui/src/library_ui.rs:448`](../ui/dr-ui/src/library_ui.rs#L448), [`ui/dr-ui/src/library_ui.rs:519`](../ui/dr-ui/src/library_ui.rs#L519), [`ui/dr-ui/src/library_ui.rs:576`](../ui/dr-ui/src/library_ui.rs#L576), [`ui/dr-ui/ui/app.slint:1089`](../ui/dr-ui/ui/app.slint#L1089), [`ui/dr-ui/ui/app.slint:778`](../ui/dr-ui/ui/app.slint#L778), [`ui/dr-ui/ui/library.slint:468`](../ui/dr-ui/ui/library.slint#L468), [`ui/dr-ui/ui/library.slint:536`](../ui/dr-ui/ui/library.slint#L536), [`ui/dr-ui/ui/library.slint:864`](../ui/dr-ui/ui/library.slint#L864) |
|
||||||
| FR-EXP-8 | [`core/dr-export/src/encode.rs:1`](../core/dr-export/src/encode.rs#L1), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1) |
|
| FR-EXP-8 | [`core/dr-export/src/encode.rs:1`](../core/dr-export/src/encode.rs#L1), [`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:409`](../core/dr-decode/src/lib.rs#L409), [`core/dr-export/src/lib.rs:125`](../core/dr-export/src/lib.rs#L125), [`core/dr-export/src/lib.rs:1`](../core/dr-export/src/lib.rs#L1), [`core/dr-gpu/src/adjust.rs:350`](../core/dr-gpu/src/adjust.rs#L350), [`ui/dr-ui/src/develop.rs:654`](../ui/dr-ui/src/develop.rs#L654), [`ui/dr-ui/src/lib.rs:317`](../ui/dr-ui/src/lib.rs#L317) |
|
| FR-EXP-9 | [`core/dr-decode/src/lib.rs:409`](../core/dr-decode/src/lib.rs#L409), [`core/dr-export/src/lib.rs:125`](../core/dr-export/src/lib.rs#L125), [`core/dr-export/src/lib.rs:1`](../core/dr-export/src/lib.rs#L1), [`core/dr-gpu/src/adjust.rs:415`](../core/dr-gpu/src/adjust.rs#L415), [`ui/dr-ui/src/develop.rs:1121`](../ui/dr-ui/src/develop.rs#L1121), [`ui/dr-ui/src/lib.rs:324`](../ui/dr-ui/src/lib.rs#L324) |
|
||||||
| 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/session.rs:128`](../core/dr-sync-nextcloud/src/session.rs#L128), [`ui/dr-ui/src/launch.rs:256`](../ui/dr-ui/src/launch.rs#L256), [`ui/dr-ui/src/launch.rs:49`](../ui/dr-ui/src/launch.rs#L49), [`ui/dr-ui/src/launch_ui.rs:344`](../ui/dr-ui/src/launch_ui.rs#L344) |
|
| 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/session.rs:128`](../core/dr-sync-nextcloud/src/session.rs#L128), [`ui/dr-ui/src/launch.rs:256`](../ui/dr-ui/src/launch.rs#L256), [`ui/dr-ui/src/launch.rs:49`](../ui/dr-ui/src/launch.rs#L49), [`ui/dr-ui/src/launch_ui.rs:344`](../ui/dr-ui/src/launch_ui.rs#L344) |
|
||||||
| FR-NC-10 | [`ui/dr-ui/src/export.rs:1`](../ui/dr-ui/src/export.rs#L1), [`ui/dr-ui/src/lib.rs:379`](../ui/dr-ui/src/lib.rs#L379), [`ui/dr-ui/src/library.rs:1448`](../ui/dr-ui/src/library.rs#L1448), [`ui/dr-ui/src/library.rs:349`](../ui/dr-ui/src/library.rs#L349), [`ui/dr-ui/src/library.rs:619`](../ui/dr-ui/src/library.rs#L619), [`ui/dr-ui/src/library.rs:813`](../ui/dr-ui/src/library.rs#L813), [`ui/dr-ui/src/library_ui.rs:1433`](../ui/dr-ui/src/library_ui.rs#L1433), [`ui/dr-ui/src/library_ui.rs:2477`](../ui/dr-ui/src/library_ui.rs#L2477), [`ui/dr-ui/src/library_ui.rs:380`](../ui/dr-ui/src/library_ui.rs#L380), [`ui/dr-ui/src/sidecar_cache.rs:1`](../ui/dr-ui/src/sidecar_cache.rs#L1) |
|
| FR-NC-10 | [`ui/dr-ui/src/export.rs:1`](../ui/dr-ui/src/export.rs#L1), [`ui/dr-ui/src/lib.rs:386`](../ui/dr-ui/src/lib.rs#L386), [`ui/dr-ui/src/library.rs:1512`](../ui/dr-ui/src/library.rs#L1512), [`ui/dr-ui/src/library.rs:398`](../ui/dr-ui/src/library.rs#L398), [`ui/dr-ui/src/library.rs:680`](../ui/dr-ui/src/library.rs#L680), [`ui/dr-ui/src/library.rs:877`](../ui/dr-ui/src/library.rs#L877), [`ui/dr-ui/src/library_ui.rs:1442`](../ui/dr-ui/src/library_ui.rs#L1442), [`ui/dr-ui/src/library_ui.rs:2494`](../ui/dr-ui/src/library_ui.rs#L2494), [`ui/dr-ui/src/library_ui.rs:389`](../ui/dr-ui/src/library_ui.rs#L389), [`ui/dr-ui/src/sidecar_cache.rs:1`](../ui/dr-ui/src/sidecar_cache.rs#L1) |
|
||||||
| FR-NC-12 | [`core/dr-sync-nextcloud/src/lib.rs:34`](../core/dr-sync-nextcloud/src/lib.rs#L34), [`core/dr-sync-nextcloud/src/lib.rs:811`](../core/dr-sync-nextcloud/src/lib.rs#L811), [`core/dr-sync/src/lib.rs:155`](../core/dr-sync/src/lib.rs#L155), [`core/dr-sync/src/lib.rs:38`](../core/dr-sync/src/lib.rs#L38), [`core/dr-sync/src/reachability.rs:1`](../core/dr-sync/src/reachability.rs#L1) |
|
| FR-NC-12 | [`core/dr-sync-nextcloud/src/lib.rs:34`](../core/dr-sync-nextcloud/src/lib.rs#L34), [`core/dr-sync-nextcloud/src/lib.rs:892`](../core/dr-sync-nextcloud/src/lib.rs#L892), [`core/dr-sync/src/lib.rs:155`](../core/dr-sync/src/lib.rs#L155), [`core/dr-sync/src/lib.rs:38`](../core/dr-sync/src/lib.rs#L38), [`core/dr-sync/src/reachability.rs:1`](../core/dr-sync/src/reachability.rs#L1) |
|
||||||
| FR-NC-2 | [`core/dr-sync-nextcloud/src/session.rs:128`](../core/dr-sync-nextcloud/src/session.rs#L128), [`core/dr-sync-nextcloud/src/session.rs:34`](../core/dr-sync-nextcloud/src/session.rs#L34) |
|
| FR-NC-2 | [`core/dr-sync-nextcloud/src/session.rs:128`](../core/dr-sync-nextcloud/src/session.rs#L128), [`core/dr-sync-nextcloud/src/session.rs:34`](../core/dr-sync-nextcloud/src/session.rs#L34) |
|
||||||
| FR-NC-3 | [`core/dr-decode/src/locate.rs:1`](../core/dr-decode/src/locate.rs#L1), [`core/dr-decode/src/preview.rs:161`](../core/dr-decode/src/preview.rs#L161), [`core/dr-sync/src/capability.rs:41`](../core/dr-sync/src/capability.rs#L41), [`core/dr-thumbs/src/lib.rs:1`](../core/dr-thumbs/src/lib.rs#L1), [`ui/dr-ui/src/library.rs:1`](../ui/dr-ui/src/library.rs#L1), [`ui/dr-ui/src/library_ui.rs:1`](../ui/dr-ui/src/library_ui.rs#L1) |
|
| FR-NC-3 | [`core/dr-decode/src/locate.rs:1`](../core/dr-decode/src/locate.rs#L1), [`core/dr-decode/src/preview.rs:161`](../core/dr-decode/src/preview.rs#L161), [`core/dr-sync/src/capability.rs:41`](../core/dr-sync/src/capability.rs#L41), [`core/dr-thumbs/src/lib.rs:1`](../core/dr-thumbs/src/lib.rs#L1), [`ui/dr-ui/src/library.rs:1`](../ui/dr-ui/src/library.rs#L1), [`ui/dr-ui/src/library_ui.rs:1`](../ui/dr-ui/src/library_ui.rs#L1) |
|
||||||
| FR-NC-4 | [`core/dr-sync-nextcloud/src/propfind.rs:100`](../core/dr-sync-nextcloud/src/propfind.rs#L100), [`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:155`](../core/dr-sync/src/lib.rs#L155), [`core/dr-sync/src/scan.rs:93`](../core/dr-sync/src/scan.rs#L93), [`ui/dr-ui/src/launch.rs:49`](../ui/dr-ui/src/launch.rs#L49) |
|
| FR-NC-4 | [`core/dr-sync-nextcloud/src/propfind.rs:100`](../core/dr-sync-nextcloud/src/propfind.rs#L100), [`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:155`](../core/dr-sync/src/lib.rs#L155), [`core/dr-sync/src/scan.rs:93`](../core/dr-sync/src/scan.rs#L93), [`ui/dr-ui/src/launch.rs:49`](../ui/dr-ui/src/launch.rs#L49) |
|
||||||
| FR-NC-5 | [`core/dr-sync-nextcloud/src/propfind.rs:51`](../core/dr-sync-nextcloud/src/propfind.rs#L51) |
|
| FR-NC-5 | [`core/dr-sync-nextcloud/src/propfind.rs:51`](../core/dr-sync-nextcloud/src/propfind.rs#L51) |
|
||||||
| FR-NC-6 | [`ui/dr-ui/src/activity.rs:1`](../ui/dr-ui/src/activity.rs#L1) |
|
| 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/schema.rs:230`](../core/dr-catalog/src/schema.rs#L230), [`core/dr-catalog/src/schema.rs:631`](../core/dr-catalog/src/schema.rs#L631), [`core/dr-types/src/selector.rs:1`](../core/dr-types/src/selector.rs#L1), [`core/dr-types/src/settings.rs:1`](../core/dr-types/src/settings.rs#L1), [`ui/dr-ui/src/collections_ui.rs:2718`](../ui/dr-ui/src/collections_ui.rs#L2718), [`ui/dr-ui/src/collections_ui.rs:438`](../ui/dr-ui/src/collections_ui.rs#L438), [`ui/dr-ui/src/collections_ui.rs:500`](../ui/dr-ui/src/collections_ui.rs#L500), [`ui/dr-ui/src/lib.rs:1408`](../ui/dr-ui/src/lib.rs#L1408), [`ui/dr-ui/src/lib.rs:2082`](../ui/dr-ui/src/lib.rs#L2082), [`ui/dr-ui/src/library.rs:1190`](../ui/dr-ui/src/library.rs#L1190), [`ui/dr-ui/src/library.rs:1213`](../ui/dr-ui/src/library.rs#L1213), [`ui/dr-ui/src/library.rs:1371`](../ui/dr-ui/src/library.rs#L1371), [`ui/dr-ui/src/library_ui.rs:1066`](../ui/dr-ui/src/library_ui.rs#L1066), [`ui/dr-ui/src/library_ui.rs:1121`](../ui/dr-ui/src/library_ui.rs#L1121), [`ui/dr-ui/src/library_ui.rs:1239`](../ui/dr-ui/src/library_ui.rs#L1239), [`ui/dr-ui/src/library_ui.rs:1358`](../ui/dr-ui/src/library_ui.rs#L1358), [`ui/dr-ui/src/library_ui.rs:1590`](../ui/dr-ui/src/library_ui.rs#L1590), [`ui/dr-ui/src/library_ui.rs:187`](../ui/dr-ui/src/library_ui.rs#L187), [`ui/dr-ui/src/library_ui.rs:191`](../ui/dr-ui/src/library_ui.rs#L191), [`ui/dr-ui/src/library_ui.rs:199`](../ui/dr-ui/src/library_ui.rs#L199), [`ui/dr-ui/src/library_ui.rs:211`](../ui/dr-ui/src/library_ui.rs#L211), [`ui/dr-ui/src/library_ui.rs:220`](../ui/dr-ui/src/library_ui.rs#L220), [`ui/dr-ui/src/library_ui.rs:281`](../ui/dr-ui/src/library_ui.rs#L281), [`ui/dr-ui/src/library_ui.rs:291`](../ui/dr-ui/src/library_ui.rs#L291), [`ui/dr-ui/src/library_ui.rs:333`](../ui/dr-ui/src/library_ui.rs#L333), [`ui/dr-ui/src/library_ui.rs:3655`](../ui/dr-ui/src/library_ui.rs#L3655), [`ui/dr-ui/src/library_ui.rs:3673`](../ui/dr-ui/src/library_ui.rs#L3673), [`ui/dr-ui/src/library_ui.rs:3685`](../ui/dr-ui/src/library_ui.rs#L3685), [`ui/dr-ui/src/library_ui.rs:396`](../ui/dr-ui/src/library_ui.rs#L396), [`ui/dr-ui/src/library_ui.rs:427`](../ui/dr-ui/src/library_ui.rs#L427), [`ui/dr-ui/src/library_ui.rs:439`](../ui/dr-ui/src/library_ui.rs#L439), [`ui/dr-ui/src/library_ui.rs:892`](../ui/dr-ui/src/library_ui.rs#L892), [`ui/dr-ui/src/library_ui.rs:965`](../ui/dr-ui/src/library_ui.rs#L965), [`ui/dr-ui/src/settings_store.rs:1`](../ui/dr-ui/src/settings_store.rs#L1), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1), [`ui/dr-ui/ui/app.slint:1695`](../ui/dr-ui/ui/app.slint#L1695), [`ui/dr-ui/ui/app.slint:468`](../ui/dr-ui/ui/app.slint#L468), [`ui/dr-ui/ui/collections.slint:249`](../ui/dr-ui/ui/collections.slint#L249), [`ui/dr-ui/ui/collections.slint:365`](../ui/dr-ui/ui/collections.slint#L365), [`ui/dr-ui/ui/collections.slint:52`](../ui/dr-ui/ui/collections.slint#L52), [`ui/dr-ui/ui/collections.slint:662`](../ui/dr-ui/ui/collections.slint#L662), [`ui/dr-ui/ui/collections.slint:84`](../ui/dr-ui/ui/collections.slint#L84), [`ui/dr-ui/ui/icons.slint:260`](../ui/dr-ui/ui/icons.slint#L260), [`ui/dr-ui/ui/library.slint:582`](../ui/dr-ui/ui/library.slint#L582) |
|
| FR-NC-6a | [`core/dr-catalog/src/cache.rs:1`](../core/dr-catalog/src/cache.rs#L1), [`core/dr-catalog/src/schema.rs:230`](../core/dr-catalog/src/schema.rs#L230), [`core/dr-catalog/src/schema.rs:631`](../core/dr-catalog/src/schema.rs#L631), [`core/dr-types/src/selector.rs:1`](../core/dr-types/src/selector.rs#L1), [`core/dr-types/src/settings.rs:1`](../core/dr-types/src/settings.rs#L1), [`ui/dr-ui/src/collections_ui.rs:2847`](../ui/dr-ui/src/collections_ui.rs#L2847), [`ui/dr-ui/src/collections_ui.rs:490`](../ui/dr-ui/src/collections_ui.rs#L490), [`ui/dr-ui/src/collections_ui.rs:552`](../ui/dr-ui/src/collections_ui.rs#L552), [`ui/dr-ui/src/lib.rs:1415`](../ui/dr-ui/src/lib.rs#L1415), [`ui/dr-ui/src/lib.rs:2095`](../ui/dr-ui/src/lib.rs#L2095), [`ui/dr-ui/src/library.rs:1254`](../ui/dr-ui/src/library.rs#L1254), [`ui/dr-ui/src/library.rs:1277`](../ui/dr-ui/src/library.rs#L1277), [`ui/dr-ui/src/library.rs:1435`](../ui/dr-ui/src/library.rs#L1435), [`ui/dr-ui/src/library_ui.rs:1075`](../ui/dr-ui/src/library_ui.rs#L1075), [`ui/dr-ui/src/library_ui.rs:1130`](../ui/dr-ui/src/library_ui.rs#L1130), [`ui/dr-ui/src/library_ui.rs:1248`](../ui/dr-ui/src/library_ui.rs#L1248), [`ui/dr-ui/src/library_ui.rs:1367`](../ui/dr-ui/src/library_ui.rs#L1367), [`ui/dr-ui/src/library_ui.rs:1599`](../ui/dr-ui/src/library_ui.rs#L1599), [`ui/dr-ui/src/library_ui.rs:195`](../ui/dr-ui/src/library_ui.rs#L195), [`ui/dr-ui/src/library_ui.rs:199`](../ui/dr-ui/src/library_ui.rs#L199), [`ui/dr-ui/src/library_ui.rs:207`](../ui/dr-ui/src/library_ui.rs#L207), [`ui/dr-ui/src/library_ui.rs:219`](../ui/dr-ui/src/library_ui.rs#L219), [`ui/dr-ui/src/library_ui.rs:228`](../ui/dr-ui/src/library_ui.rs#L228), [`ui/dr-ui/src/library_ui.rs:290`](../ui/dr-ui/src/library_ui.rs#L290), [`ui/dr-ui/src/library_ui.rs:300`](../ui/dr-ui/src/library_ui.rs#L300), [`ui/dr-ui/src/library_ui.rs:342`](../ui/dr-ui/src/library_ui.rs#L342), [`ui/dr-ui/src/library_ui.rs:3709`](../ui/dr-ui/src/library_ui.rs#L3709), [`ui/dr-ui/src/library_ui.rs:3727`](../ui/dr-ui/src/library_ui.rs#L3727), [`ui/dr-ui/src/library_ui.rs:3739`](../ui/dr-ui/src/library_ui.rs#L3739), [`ui/dr-ui/src/library_ui.rs:405`](../ui/dr-ui/src/library_ui.rs#L405), [`ui/dr-ui/src/library_ui.rs:436`](../ui/dr-ui/src/library_ui.rs#L436), [`ui/dr-ui/src/library_ui.rs:448`](../ui/dr-ui/src/library_ui.rs#L448), [`ui/dr-ui/src/library_ui.rs:901`](../ui/dr-ui/src/library_ui.rs#L901), [`ui/dr-ui/src/library_ui.rs:974`](../ui/dr-ui/src/library_ui.rs#L974), [`ui/dr-ui/src/settings_store.rs:1`](../ui/dr-ui/src/settings_store.rs#L1), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1), [`ui/dr-ui/ui/app.slint:1880`](../ui/dr-ui/ui/app.slint#L1880), [`ui/dr-ui/ui/app.slint:486`](../ui/dr-ui/ui/app.slint#L486), [`ui/dr-ui/ui/collections.slint:249`](../ui/dr-ui/ui/collections.slint#L249), [`ui/dr-ui/ui/collections.slint:369`](../ui/dr-ui/ui/collections.slint#L369), [`ui/dr-ui/ui/collections.slint:52`](../ui/dr-ui/ui/collections.slint#L52), [`ui/dr-ui/ui/collections.slint:682`](../ui/dr-ui/ui/collections.slint#L682), [`ui/dr-ui/ui/collections.slint:84`](../ui/dr-ui/ui/collections.slint#L84), [`ui/dr-ui/ui/icons.slint:260`](../ui/dr-ui/ui/icons.slint#L260), [`ui/dr-ui/ui/library.slint:582`](../ui/dr-ui/ui/library.slint#L582) |
|
||||||
| FR-NC-6b | [`ui/dr-ui/src/library_ui.rs:1121`](../ui/dr-ui/src/library_ui.rs#L1121) |
|
| FR-NC-6b | [`ui/dr-ui/src/library_ui.rs:1130`](../ui/dr-ui/src/library_ui.rs#L1130) |
|
||||||
| FR-NC-6c | [`core/dr-sync-nextcloud/src/desktop_client.rs:30`](../core/dr-sync-nextcloud/src/desktop_client.rs#L30), [`core/dr-types/src/lib.rs:115`](../core/dr-types/src/lib.rs#L115), [`core/dr-types/src/lib.rs:197`](../core/dr-types/src/lib.rs#L197), [`ui/dr-ui/src/activity.rs:1`](../ui/dr-ui/src/activity.rs#L1), [`ui/dr-ui/src/collections_ui.rs:2718`](../ui/dr-ui/src/collections_ui.rs#L2718), [`ui/dr-ui/src/collections_ui.rs:438`](../ui/dr-ui/src/collections_ui.rs#L438), [`ui/dr-ui/src/collections_ui.rs:500`](../ui/dr-ui/src/collections_ui.rs#L500), [`ui/dr-ui/src/library_ui.rs:892`](../ui/dr-ui/src/library_ui.rs#L892), [`ui/dr-ui/src/library_ui.rs:965`](../ui/dr-ui/src/library_ui.rs#L965), [`ui/dr-ui/ui/collections.slint:249`](../ui/dr-ui/ui/collections.slint#L249), [`ui/dr-ui/ui/collections.slint:662`](../ui/dr-ui/ui/collections.slint#L662), [`ui/dr-ui/ui/icons.slint:260`](../ui/dr-ui/ui/icons.slint#L260) |
|
| FR-NC-6c | [`core/dr-sync-nextcloud/src/desktop_client.rs:30`](../core/dr-sync-nextcloud/src/desktop_client.rs#L30), [`core/dr-types/src/lib.rs:115`](../core/dr-types/src/lib.rs#L115), [`core/dr-types/src/lib.rs:197`](../core/dr-types/src/lib.rs#L197), [`ui/dr-ui/src/activity.rs:1`](../ui/dr-ui/src/activity.rs#L1), [`ui/dr-ui/src/collections_ui.rs:2847`](../ui/dr-ui/src/collections_ui.rs#L2847), [`ui/dr-ui/src/collections_ui.rs:490`](../ui/dr-ui/src/collections_ui.rs#L490), [`ui/dr-ui/src/collections_ui.rs:552`](../ui/dr-ui/src/collections_ui.rs#L552), [`ui/dr-ui/src/library_ui.rs:901`](../ui/dr-ui/src/library_ui.rs#L901), [`ui/dr-ui/src/library_ui.rs:974`](../ui/dr-ui/src/library_ui.rs#L974), [`ui/dr-ui/ui/collections.slint:249`](../ui/dr-ui/ui/collections.slint#L249), [`ui/dr-ui/ui/collections.slint:682`](../ui/dr-ui/ui/collections.slint#L682), [`ui/dr-ui/ui/icons.slint:260`](../ui/dr-ui/ui/icons.slint#L260) |
|
||||||
| FR-NC-7 | [`core/dr-sync-nextcloud/src/lib.rs:95`](../core/dr-sync-nextcloud/src/lib.rs#L95), [`ui/dr-ui/src/derived_sync.rs:1`](../ui/dr-ui/src/derived_sync.rs#L1) |
|
| FR-NC-7 | [`core/dr-sync-nextcloud/src/lib.rs:95`](../core/dr-sync-nextcloud/src/lib.rs#L95), [`ui/dr-ui/src/derived_sync.rs:1`](../ui/dr-ui/src/derived_sync.rs#L1) |
|
||||||
| FR-NC-8 | [`core/dr-pipeline/src/sidecar.rs:108`](../core/dr-pipeline/src/sidecar.rs#L108), [`core/dr-pipeline/src/sidecar.rs:89`](../core/dr-pipeline/src/sidecar.rs#L89), [`ui/dr-ui/src/lib.rs:1377`](../ui/dr-ui/src/lib.rs#L1377), [`ui/dr-ui/src/library.rs:291`](../ui/dr-ui/src/library.rs#L291), [`ui/dr-ui/src/library_ui.rs:348`](../ui/dr-ui/src/library_ui.rs#L348) |
|
| FR-NC-8 | [`core/dr-pipeline/src/sidecar.rs:109`](../core/dr-pipeline/src/sidecar.rs#L109), [`core/dr-pipeline/src/sidecar.rs:90`](../core/dr-pipeline/src/sidecar.rs#L90), [`ui/dr-ui/src/lib.rs:1384`](../ui/dr-ui/src/lib.rs#L1384), [`ui/dr-ui/src/library.rs:340`](../ui/dr-ui/src/library.rs#L340), [`ui/dr-ui/src/library_ui.rs:357`](../ui/dr-ui/src/library_ui.rs#L357) |
|
||||||
| FR-NC-9 | [`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-pipeline/src/sidecar.rs:212`](../core/dr-pipeline/src/sidecar.rs#L212), [`ui/dr-ui/src/library.rs:619`](../ui/dr-ui/src/library.rs#L619), [`ui/dr-ui/src/library.rs:746`](../ui/dr-ui/src/library.rs#L746) |
|
| FR-NC-9 | [`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-pipeline/src/sidecar.rs:147`](../core/dr-pipeline/src/sidecar.rs#L147), [`core/dr-pipeline/src/sidecar.rs:301`](../core/dr-pipeline/src/sidecar.rs#L301), [`ui/dr-ui/src/library.rs:680`](../ui/dr-ui/src/library.rs#L680), [`ui/dr-ui/src/library.rs:810`](../ui/dr-ui/src/library.rs#L810) |
|
||||||
| FR-PLAT-AND-1 | [`core/dr-types/src/lib.rs:49`](../core/dr-types/src/lib.rs#L49) |
|
| FR-PLAT-AND-1 | [`core/dr-types/src/lib.rs:49`](../core/dr-types/src/lib.rs#L49) |
|
||||||
| FR-PLAT-AND-3 | [`core/dr-catalog/src/jobs.rs:1`](../core/dr-catalog/src/jobs.rs#L1) |
|
| FR-PLAT-AND-3 | [`core/dr-catalog/src/jobs.rs:1`](../core/dr-catalog/src/jobs.rs#L1) |
|
||||||
| FR-PLAT-LIN-1 | [`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) |
|
| FR-PLAT-LIN-1 | [`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) |
|
||||||
| FR-RAW-1 | [`core/dr-decode/src/lib.rs:198`](../core/dr-decode/src/lib.rs#L198), [`core/dr-types/src/lib.rs:125`](../core/dr-types/src/lib.rs#L125), [`core/dr-types/src/lib.rs:196`](../core/dr-types/src/lib.rs#L196) |
|
| FR-RAW-1 | [`core/dr-decode/src/lib.rs:198`](../core/dr-decode/src/lib.rs#L198), [`core/dr-types/src/lib.rs:125`](../core/dr-types/src/lib.rs#L125), [`core/dr-types/src/lib.rs:196`](../core/dr-types/src/lib.rs#L196) |
|
||||||
| FR-RAW-3 | [`core/dr-decode/src/lib.rs:409`](../core/dr-decode/src/lib.rs#L409), [`core/dr-decode/src/lib.rs:94`](../core/dr-decode/src/lib.rs#L94) |
|
| FR-RAW-3 | [`core/dr-decode/src/lib.rs:409`](../core/dr-decode/src/lib.rs#L409), [`core/dr-decode/src/lib.rs:94`](../core/dr-decode/src/lib.rs#L94) |
|
||||||
| FR-RAW-4 | [`core/dr-decode/src/error.rs:1`](../core/dr-decode/src/error.rs#L1), [`ui/dr-ui/src/lib.rs:170`](../ui/dr-ui/src/lib.rs#L170) |
|
| FR-RAW-4 | [`core/dr-decode/src/error.rs:1`](../core/dr-decode/src/error.rs#L1), [`ui/dr-ui/src/lib.rs:172`](../ui/dr-ui/src/lib.rs#L172) |
|
||||||
| FR-RAW-5 | [`core/dr-decode/src/lib.rs:122`](../core/dr-decode/src/lib.rs#L122), [`core/dr-gpu/src/demosaic.rs:34`](../core/dr-gpu/src/demosaic.rs#L34), [`core/dr-gpu/src/demosaic.rs:573`](../core/dr-gpu/src/demosaic.rs#L573), [`core/dr-gpu/src/demosaic.rs:652`](../core/dr-gpu/src/demosaic.rs#L652), [`core/dr-gpu/src/demosaic.rs:776`](../core/dr-gpu/src/demosaic.rs#L776) |
|
| FR-RAW-5 | [`core/dr-decode/src/lib.rs:122`](../core/dr-decode/src/lib.rs#L122), [`core/dr-gpu/src/demosaic.rs:34`](../core/dr-gpu/src/demosaic.rs#L34), [`core/dr-gpu/src/demosaic.rs:573`](../core/dr-gpu/src/demosaic.rs#L573), [`core/dr-gpu/src/demosaic.rs:652`](../core/dr-gpu/src/demosaic.rs#L652), [`core/dr-gpu/src/demosaic.rs:776`](../core/dr-gpu/src/demosaic.rs#L776) |
|
||||||
| FR-UI-1 | [`ui/dr-ui/src/lib.rs:2164`](../ui/dr-ui/src/lib.rs#L2164), [`ui/dr-ui/src/lib.rs:62`](../ui/dr-ui/src/lib.rs#L62), [`ui/dr-ui/ui/library.slint:628`](../ui/dr-ui/ui/library.slint#L628) |
|
| FR-UI-1 | [`ui/dr-ui/src/lib.rs:2177`](../ui/dr-ui/src/lib.rs#L2177), [`ui/dr-ui/src/lib.rs:64`](../ui/dr-ui/src/lib.rs#L64), [`ui/dr-ui/ui/library.slint:628`](../ui/dr-ui/ui/library.slint#L628) |
|
||||||
| FR-UI-2 | [`ui/dr-ui/src/collections_ui.rs:1312`](../ui/dr-ui/src/collections_ui.rs#L1312), [`ui/dr-ui/src/collections_ui.rs:1326`](../ui/dr-ui/src/collections_ui.rs#L1326), [`ui/dr-ui/src/collections_ui.rs:1371`](../ui/dr-ui/src/collections_ui.rs#L1371), [`ui/dr-ui/src/collections_ui.rs:1381`](../ui/dr-ui/src/collections_ui.rs#L1381), [`ui/dr-ui/src/collections_ui.rs:338`](../ui/dr-ui/src/collections_ui.rs#L338), [`ui/dr-ui/src/collections_ui.rs:366`](../ui/dr-ui/src/collections_ui.rs#L366), [`ui/dr-ui/src/collections_ui.rs:70`](../ui/dr-ui/src/collections_ui.rs#L70), [`ui/dr-ui/src/collections_ui.rs:805`](../ui/dr-ui/src/collections_ui.rs#L805), [`ui/dr-ui/src/collections_ui.rs:815`](../ui/dr-ui/src/collections_ui.rs#L815), [`ui/dr-ui/src/collections_ui.rs:98`](../ui/dr-ui/src/collections_ui.rs#L98), [`ui/dr-ui/src/lib.rs:62`](../ui/dr-ui/src/lib.rs#L62), [`ui/dr-ui/src/library_ui.rs:199`](../ui/dr-ui/src/library_ui.rs#L199), [`ui/dr-ui/src/library_ui.rs:3685`](../ui/dr-ui/src/library_ui.rs#L3685), [`ui/dr-ui/ui/app.slint:479`](../ui/dr-ui/ui/app.slint#L479), [`ui/dr-ui/ui/app.slint:486`](../ui/dr-ui/ui/app.slint#L486), [`ui/dr-ui/ui/library.slint:1418`](../ui/dr-ui/ui/library.slint#L1418), [`ui/dr-ui/ui/library.slint:456`](../ui/dr-ui/ui/library.slint#L456), [`ui/dr-ui/ui/library.slint:492`](../ui/dr-ui/ui/library.slint#L492), [`ui/dr-ui/ui/library.slint:766`](../ui/dr-ui/ui/library.slint#L766), [`ui/dr-ui/ui/library.slint:773`](../ui/dr-ui/ui/library.slint#L773), [`ui/dr-ui/ui/library.slint:779`](../ui/dr-ui/ui/library.slint#L779) |
|
| FR-UI-2 | [`ui/dr-ui/src/collections_ui.rs:1364`](../ui/dr-ui/src/collections_ui.rs#L1364), [`ui/dr-ui/src/collections_ui.rs:1378`](../ui/dr-ui/src/collections_ui.rs#L1378), [`ui/dr-ui/src/collections_ui.rs:1423`](../ui/dr-ui/src/collections_ui.rs#L1423), [`ui/dr-ui/src/collections_ui.rs:1433`](../ui/dr-ui/src/collections_ui.rs#L1433), [`ui/dr-ui/src/collections_ui.rs:390`](../ui/dr-ui/src/collections_ui.rs#L390), [`ui/dr-ui/src/collections_ui.rs:418`](../ui/dr-ui/src/collections_ui.rs#L418), [`ui/dr-ui/src/collections_ui.rs:70`](../ui/dr-ui/src/collections_ui.rs#L70), [`ui/dr-ui/src/collections_ui.rs:857`](../ui/dr-ui/src/collections_ui.rs#L857), [`ui/dr-ui/src/collections_ui.rs:867`](../ui/dr-ui/src/collections_ui.rs#L867), [`ui/dr-ui/src/collections_ui.rs:98`](../ui/dr-ui/src/collections_ui.rs#L98), [`ui/dr-ui/src/lib.rs:64`](../ui/dr-ui/src/lib.rs#L64), [`ui/dr-ui/src/library_ui.rs:207`](../ui/dr-ui/src/library_ui.rs#L207), [`ui/dr-ui/src/library_ui.rs:3739`](../ui/dr-ui/src/library_ui.rs#L3739), [`ui/dr-ui/ui/app.slint:497`](../ui/dr-ui/ui/app.slint#L497), [`ui/dr-ui/ui/app.slint:504`](../ui/dr-ui/ui/app.slint#L504), [`ui/dr-ui/ui/library.slint:1456`](../ui/dr-ui/ui/library.slint#L1456), [`ui/dr-ui/ui/library.slint:456`](../ui/dr-ui/ui/library.slint#L456), [`ui/dr-ui/ui/library.slint:492`](../ui/dr-ui/ui/library.slint#L492), [`ui/dr-ui/ui/library.slint:766`](../ui/dr-ui/ui/library.slint#L766), [`ui/dr-ui/ui/library.slint:773`](../ui/dr-ui/ui/library.slint#L773), [`ui/dr-ui/ui/library.slint:779`](../ui/dr-ui/ui/library.slint#L779) |
|
||||||
| FR-UI-3 | [`ui/dr-ui/ui/collections.slint:4`](../ui/dr-ui/ui/collections.slint#L4), [`ui/dr-ui/ui/collections.slint:662`](../ui/dr-ui/ui/collections.slint#L662) |
|
| FR-UI-3 | [`ui/dr-ui/ui/collections.slint:4`](../ui/dr-ui/ui/collections.slint#L4), [`ui/dr-ui/ui/collections.slint:682`](../ui/dr-ui/ui/collections.slint#L682) |
|
||||||
| FR-UI-4 | [`ui/dr-ui/src/collections_ui.rs:1312`](../ui/dr-ui/src/collections_ui.rs#L1312), [`ui/dr-ui/src/collections_ui.rs:1326`](../ui/dr-ui/src/collections_ui.rs#L1326), [`ui/dr-ui/src/collections_ui.rs:1371`](../ui/dr-ui/src/collections_ui.rs#L1371), [`ui/dr-ui/src/collections_ui.rs:1381`](../ui/dr-ui/src/collections_ui.rs#L1381), [`ui/dr-ui/src/collections_ui.rs:1408`](../ui/dr-ui/src/collections_ui.rs#L1408), [`ui/dr-ui/src/collections_ui.rs:338`](../ui/dr-ui/src/collections_ui.rs#L338), [`ui/dr-ui/src/collections_ui.rs:366`](../ui/dr-ui/src/collections_ui.rs#L366), [`ui/dr-ui/src/collections_ui.rs:70`](../ui/dr-ui/src/collections_ui.rs#L70), [`ui/dr-ui/src/collections_ui.rs:805`](../ui/dr-ui/src/collections_ui.rs#L805), [`ui/dr-ui/src/collections_ui.rs:815`](../ui/dr-ui/src/collections_ui.rs#L815), [`ui/dr-ui/src/collections_ui.rs:98`](../ui/dr-ui/src/collections_ui.rs#L98), [`ui/dr-ui/src/library_ui.rs:3673`](../ui/dr-ui/src/library_ui.rs#L3673), [`ui/dr-ui/src/library_ui.rs:3685`](../ui/dr-ui/src/library_ui.rs#L3685), [`ui/dr-ui/ui/app.slint:1205`](../ui/dr-ui/ui/app.slint#L1205), [`ui/dr-ui/ui/app.slint:474`](../ui/dr-ui/ui/app.slint#L474), [`ui/dr-ui/ui/app.slint:486`](../ui/dr-ui/ui/app.slint#L486), [`ui/dr-ui/ui/library.slint:1418`](../ui/dr-ui/ui/library.slint#L1418), [`ui/dr-ui/ui/library.slint:456`](../ui/dr-ui/ui/library.slint#L456), [`ui/dr-ui/ui/library.slint:492`](../ui/dr-ui/ui/library.slint#L492), [`ui/dr-ui/ui/library.slint:511`](../ui/dr-ui/ui/library.slint#L511), [`ui/dr-ui/ui/library.slint:766`](../ui/dr-ui/ui/library.slint#L766), [`ui/dr-ui/ui/library.slint:773`](../ui/dr-ui/ui/library.slint#L773), [`ui/dr-ui/ui/library.slint:779`](../ui/dr-ui/ui/library.slint#L779) |
|
| FR-UI-4 | [`ui/dr-ui/src/collections_ui.rs:1364`](../ui/dr-ui/src/collections_ui.rs#L1364), [`ui/dr-ui/src/collections_ui.rs:1378`](../ui/dr-ui/src/collections_ui.rs#L1378), [`ui/dr-ui/src/collections_ui.rs:1423`](../ui/dr-ui/src/collections_ui.rs#L1423), [`ui/dr-ui/src/collections_ui.rs:1433`](../ui/dr-ui/src/collections_ui.rs#L1433), [`ui/dr-ui/src/collections_ui.rs:1460`](../ui/dr-ui/src/collections_ui.rs#L1460), [`ui/dr-ui/src/collections_ui.rs:390`](../ui/dr-ui/src/collections_ui.rs#L390), [`ui/dr-ui/src/collections_ui.rs:418`](../ui/dr-ui/src/collections_ui.rs#L418), [`ui/dr-ui/src/collections_ui.rs:70`](../ui/dr-ui/src/collections_ui.rs#L70), [`ui/dr-ui/src/collections_ui.rs:857`](../ui/dr-ui/src/collections_ui.rs#L857), [`ui/dr-ui/src/collections_ui.rs:867`](../ui/dr-ui/src/collections_ui.rs#L867), [`ui/dr-ui/src/collections_ui.rs:98`](../ui/dr-ui/src/collections_ui.rs#L98), [`ui/dr-ui/src/library_ui.rs:3727`](../ui/dr-ui/src/library_ui.rs#L3727), [`ui/dr-ui/src/library_ui.rs:3739`](../ui/dr-ui/src/library_ui.rs#L3739), [`ui/dr-ui/ui/app.slint:1296`](../ui/dr-ui/ui/app.slint#L1296), [`ui/dr-ui/ui/app.slint:492`](../ui/dr-ui/ui/app.slint#L492), [`ui/dr-ui/ui/app.slint:504`](../ui/dr-ui/ui/app.slint#L504), [`ui/dr-ui/ui/library.slint:1456`](../ui/dr-ui/ui/library.slint#L1456), [`ui/dr-ui/ui/library.slint:456`](../ui/dr-ui/ui/library.slint#L456), [`ui/dr-ui/ui/library.slint:492`](../ui/dr-ui/ui/library.slint#L492), [`ui/dr-ui/ui/library.slint:511`](../ui/dr-ui/ui/library.slint#L511), [`ui/dr-ui/ui/library.slint:766`](../ui/dr-ui/ui/library.slint#L766), [`ui/dr-ui/ui/library.slint:773`](../ui/dr-ui/ui/library.slint#L773), [`ui/dr-ui/ui/library.slint:779`](../ui/dr-ui/ui/library.slint#L779) |
|
||||||
| FR-UI-5 | [`ui/dr-ui/src/collections_ui.rs:1`](../ui/dr-ui/src/collections_ui.rs#L1), [`ui/dr-ui/src/lib.rs:2198`](../ui/dr-ui/src/lib.rs#L2198), [`ui/dr-ui/ui/collections.slint:4`](../ui/dr-ui/ui/collections.slint#L4) |
|
| FR-UI-5 | [`ui/dr-ui/src/collections_ui.rs:1`](../ui/dr-ui/src/collections_ui.rs#L1), [`ui/dr-ui/src/lib.rs:2211`](../ui/dr-ui/src/lib.rs#L2211), [`ui/dr-ui/ui/collections.slint:4`](../ui/dr-ui/ui/collections.slint#L4) |
|
||||||
| FR-UI-7 | [`core/dr-pipeline/src/descriptor.rs:100`](../core/dr-pipeline/src/descriptor.rs#L100), [`core/dr-pipeline/src/framing.rs:256`](../core/dr-pipeline/src/framing.rs#L256) |
|
| FR-UI-7 | [`core/dr-pipeline/src/descriptor.rs:100`](../core/dr-pipeline/src/descriptor.rs#L100), [`core/dr-pipeline/src/framing.rs:256`](../core/dr-pipeline/src/framing.rs#L256) |
|
||||||
| NFR-ARCH-2 | [`core/dr-catalog/src/jobs.rs:1`](../core/dr-catalog/src/jobs.rs#L1) |
|
| NFR-ARCH-2 | [`core/dr-catalog/src/jobs.rs:1`](../core/dr-catalog/src/jobs.rs#L1) |
|
||||||
| NFR-ARCH-3 | [`ui/dr-ui/src/export.rs:1490`](../ui/dr-ui/src/export.rs#L1490), [`ui/dr-ui/src/export.rs:1516`](../ui/dr-ui/src/export.rs#L1516), [`ui/dr-ui/src/export.rs:410`](../ui/dr-ui/src/export.rs#L410), [`ui/dr-ui/src/export.rs:436`](../ui/dr-ui/src/export.rs#L436), [`ui/dr-ui/src/lib.rs:1682`](../ui/dr-ui/src/lib.rs#L1682), [`ui/dr-ui/ui/app.slint:724`](../ui/dr-ui/ui/app.slint#L724), [`ui/dr-ui/ui/library.slint:536`](../ui/dr-ui/ui/library.slint#L536) |
|
| NFR-ARCH-3 | [`ui/dr-ui/src/export.rs:1490`](../ui/dr-ui/src/export.rs#L1490), [`ui/dr-ui/src/export.rs:1516`](../ui/dr-ui/src/export.rs#L1516), [`ui/dr-ui/src/export.rs:410`](../ui/dr-ui/src/export.rs#L410), [`ui/dr-ui/src/export.rs:436`](../ui/dr-ui/src/export.rs#L436), [`ui/dr-ui/src/lib.rs:1689`](../ui/dr-ui/src/lib.rs#L1689), [`ui/dr-ui/ui/app.slint:789`](../ui/dr-ui/ui/app.slint#L789), [`ui/dr-ui/ui/library.slint:536`](../ui/dr-ui/ui/library.slint#L536) |
|
||||||
| 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), [`ui/dr-ui/src/export.rs:500`](../ui/dr-ui/src/export.rs#L500) |
|
| 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), [`ui/dr-ui/src/export.rs:500`](../ui/dr-ui/src/export.rs#L500) |
|
||||||
| NFR-OPS-1 | [`tools/traceability/src/lib.rs:266`](../tools/traceability/src/lib.rs#L266) |
|
| NFR-OPS-1 | [`tools/traceability/src/lib.rs:266`](../tools/traceability/src/lib.rs#L266) |
|
||||||
| 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/traceability/src/lib.rs:479`](../tools/traceability/src/lib.rs#L479) |
|
| 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/traceability/src/lib.rs:479`](../tools/traceability/src/lib.rs#L479) |
|
||||||
| NFR-P13 | [`core/dr-decode/src/preview.rs:134`](../core/dr-decode/src/preview.rs#L134) |
|
| NFR-P13 | [`core/dr-decode/src/preview.rs:134`](../core/dr-decode/src/preview.rs#L134) |
|
||||||
| NFR-P9 | [`ui/dr-ui/src/collections_ui.rs:1`](../ui/dr-ui/src/collections_ui.rs#L1), [`ui/dr-ui/src/export.rs:879`](../ui/dr-ui/src/export.rs#L879), [`ui/dr-ui/src/library.rs:1`](../ui/dr-ui/src/library.rs#L1), [`ui/dr-ui/src/library_ui.rs:1`](../ui/dr-ui/src/library_ui.rs#L1), [`ui/dr-ui/src/trash.rs:1`](../ui/dr-ui/src/trash.rs#L1) |
|
| NFR-P9 | [`ui/dr-ui/src/collections_ui.rs:1`](../ui/dr-ui/src/collections_ui.rs#L1), [`ui/dr-ui/src/export.rs:879`](../ui/dr-ui/src/export.rs#L879), [`ui/dr-ui/src/library.rs:1`](../ui/dr-ui/src/library.rs#L1), [`ui/dr-ui/src/library_ui.rs:1`](../ui/dr-ui/src/library_ui.rs#L1), [`ui/dr-ui/src/trash.rs:1`](../ui/dr-ui/src/trash.rs#L1) |
|
||||||
| NFR-PORT-1 | [`core/dr-catalog/src/walk.rs:1`](../core/dr-catalog/src/walk.rs#L1), [`core/dr-types/src/lib.rs:265`](../core/dr-types/src/lib.rs#L265), [`core/dr-types/src/lib.rs:298`](../core/dr-types/src/lib.rs#L298) |
|
| NFR-PORT-1 | [`core/dr-catalog/src/walk.rs:1`](../core/dr-catalog/src/walk.rs#L1), [`core/dr-types/src/lib.rs:265`](../core/dr-types/src/lib.rs#L265), [`core/dr-types/src/lib.rs:298`](../core/dr-types/src/lib.rs#L298) |
|
||||||
| NFR-R1 | [`core/dr-catalog/src/sync.rs:1`](../core/dr-catalog/src/sync.rs#L1), [`ui/dr-ui/src/library.rs:813`](../ui/dr-ui/src/library.rs#L813) |
|
| NFR-R1 | [`core/dr-catalog/src/sync.rs:1`](../core/dr-catalog/src/sync.rs#L1), [`ui/dr-ui/src/library.rs:877`](../ui/dr-ui/src/library.rs#L877) |
|
||||||
| NFR-R2 | [`core/dr-catalog/src/trash.rs:1`](../core/dr-catalog/src/trash.rs#L1) |
|
| NFR-R2 | [`core/dr-catalog/src/trash.rs:1`](../core/dr-catalog/src/trash.rs#L1) |
|
||||||
| 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/schema.rs:1`](../core/dr-catalog/src/schema.rs#L1) |
|
| 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/schema.rs:1`](../core/dr-catalog/src/schema.rs#L1) |
|
||||||
| NFR-R7 | [`core/dr-gpu/src/error.rs:1`](../core/dr-gpu/src/error.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-R8 | [`core/dr-gpu/src/error.rs:1`](../core/dr-gpu/src/error.rs#L1) |
|
||||||
| NFR-RES-1 | [`core/dr-pipeline/src/history.rs:55`](../core/dr-pipeline/src/history.rs#L55), [`ui/dr-ui/src/lib.rs:54`](../ui/dr-ui/src/lib.rs#L54) |
|
| NFR-RES-1 | [`core/dr-pipeline/src/history.rs:55`](../core/dr-pipeline/src/history.rs#L55), [`ui/dr-ui/src/lib.rs:56`](../ui/dr-ui/src/lib.rs#L56) |
|
||||||
| NFR-RES-4 | [`core/dr-catalog/src/cache.rs:1`](../core/dr-catalog/src/cache.rs#L1), [`core/dr-catalog/src/schema.rs:230`](../core/dr-catalog/src/schema.rs#L230), [`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:376`](../core/dr-thumbs/src/lib.rs#L376) |
|
| NFR-RES-4 | [`core/dr-catalog/src/cache.rs:1`](../core/dr-catalog/src/cache.rs#L1), [`core/dr-catalog/src/schema.rs:230`](../core/dr-catalog/src/schema.rs#L230), [`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:376`](../core/dr-thumbs/src/lib.rs#L376) |
|
||||||
| NFR-SEC-1 | [`core/dr-decode/src/error.rs:1`](../core/dr-decode/src/error.rs#L1) |
|
| NFR-SEC-1 | [`core/dr-decode/src/error.rs:1`](../core/dr-decode/src/error.rs#L1) |
|
||||||
| R1 | [`tools/traceability/src/lib.rs:495`](../tools/traceability/src/lib.rs#L495), [`tools/traceability/src/lib.rs:499`](../tools/traceability/src/lib.rs#L499) |
|
| R1 | [`tools/traceability/src/lib.rs:495`](../tools/traceability/src/lib.rs#L495), [`tools/traceability/src/lib.rs:499`](../tools/traceability/src/lib.rs#L499) |
|
||||||
| R4 | [`core/dr-gpu/src/lib.rs:210`](../core/dr-gpu/src/lib.rs#L210) |
|
| R4 | [`core/dr-gpu/src/lib.rs:211`](../core/dr-gpu/src/lib.rs#L211) |
|
||||||
|
|
||||||
## Not yet tagged
|
## Not yet tagged
|
||||||
|
|
||||||
|
|||||||
@@ -535,4 +535,182 @@ mod tests {
|
|||||||
stronger.prior.strength = 0.1;
|
stronger.prior.strength = 0.1;
|
||||||
assert_eq!(tuning_hash(&base), tuning_hash(&stronger));
|
assert_eq!(tuning_hash(&base), tuning_hash(&stronger));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
// On a device, end to end
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// A bright disc on a dark ground: one unambiguous boundary, which is the
|
||||||
|
/// backlit-silhouette control case from docs/segmentation.md §9.
|
||||||
|
fn disc(size: u32) -> Vec<u8> {
|
||||||
|
let r = size as f32 * 0.28;
|
||||||
|
let c = size as f32 / 2.0;
|
||||||
|
let mut out = Vec::with_capacity((size * size) as usize * 4);
|
||||||
|
for y in 0..size {
|
||||||
|
for x in 0..size {
|
||||||
|
let d = ((x as f32 + 0.5 - c).powi(2) + (y as f32 + 0.5 - c).powi(2)).sqrt();
|
||||||
|
let v = if d < r { 230 } else { 30 };
|
||||||
|
out.extend_from_slice(&[v, v, v, 255]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
fn context() -> Option<dr_gpu::GpuContext> {
|
||||||
|
pollster::block_on(dr_gpu::GpuContext::new_headless()).ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The whole arm-A chain on a real adapter: watershed, region graph, merge
|
||||||
|
/// tree, and a click landing on the disc rather than on the ground.
|
||||||
|
///
|
||||||
|
/// The CPU tests above use hand-built fields, which cannot catch a
|
||||||
|
/// watershed that produces nothing, a proxy scaled the wrong way, or a
|
||||||
|
/// click transformed into the wrong pixel.
|
||||||
|
#[test]
|
||||||
|
fn a_real_segmentation_separates_the_disc_from_the_ground() {
|
||||||
|
let Some(ctx) = context() else {
|
||||||
|
eprintln!("no adapter; skipping");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
const SIZE: u32 = 256;
|
||||||
|
let rgba = disc(SIZE);
|
||||||
|
let source = dr_gpu::DemosaicedImage::from_rgba8(&ctx, &rgba, SIZE, SIZE).expect("upload");
|
||||||
|
let rgb: Vec<f32> = rgba
|
||||||
|
.chunks_exact(4)
|
||||||
|
.flat_map(|p| [p[0] as f32 / 255.0, p[1] as f32 / 255.0, p[2] as f32 / 255.0])
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Arm A alone. The model has no COCO class for "grey disc", so running
|
||||||
|
// it here would cost half a second to contribute nothing — and the
|
||||||
|
// point of this test is the watershed half.
|
||||||
|
let options = Options {
|
||||||
|
semantic: false,
|
||||||
|
..Options::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut seg = compute(&ctx, &source, &rgb, SIZE as usize, SIZE as usize, &options)
|
||||||
|
.expect("segmentation");
|
||||||
|
assert!(seg.region_count() > 1, "a boundary should make regions");
|
||||||
|
|
||||||
|
// Coarse enough that the disc is one region rather than several.
|
||||||
|
seg.set_level(4);
|
||||||
|
|
||||||
|
let centre = seg.group_at(0.5, 0.5).expect("centre is in frame");
|
||||||
|
let corner = seg.group_at(0.04, 0.04).expect("corner is in frame");
|
||||||
|
assert_ne!(
|
||||||
|
centre, corner,
|
||||||
|
"the disc and the ground must not be one group"
|
||||||
|
);
|
||||||
|
|
||||||
|
// And the selection must be the disc, not the whole frame: a mask that
|
||||||
|
// covers everything is the failure mode a "they differ" assertion on
|
||||||
|
// its own would not catch.
|
||||||
|
let selected = seg.regions_at(0.5, 0.5);
|
||||||
|
assert!(!selected.is_empty());
|
||||||
|
assert!(
|
||||||
|
selected.len() < seg.region_count(),
|
||||||
|
"selecting the disc should not select every region"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn the_overlay_matches_the_segmentation_it_describes() {
|
||||||
|
let Some(ctx) = context() else {
|
||||||
|
eprintln!("no adapter; skipping");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
const SIZE: u32 = 128;
|
||||||
|
let rgba = disc(SIZE);
|
||||||
|
let source = dr_gpu::DemosaicedImage::from_rgba8(&ctx, &rgba, SIZE, SIZE).expect("upload");
|
||||||
|
let rgb: Vec<f32> = rgba
|
||||||
|
.chunks_exact(4)
|
||||||
|
.flat_map(|p| [p[0] as f32 / 255.0, p[1] as f32 / 255.0, p[2] as f32 / 255.0])
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let options = Options {
|
||||||
|
semantic: false,
|
||||||
|
..Options::default()
|
||||||
|
};
|
||||||
|
let mut seg = compute(&ctx, &source, &rgb, SIZE as usize, SIZE as usize, &options)
|
||||||
|
.expect("segmentation");
|
||||||
|
seg.set_level(4);
|
||||||
|
|
||||||
|
let (pixels, w, h) = seg.overlay_rgba();
|
||||||
|
assert_eq!(pixels.len(), (w * h) as usize * 4);
|
||||||
|
|
||||||
|
// The disc's centre and the ground must be drawn differently, or the
|
||||||
|
// overlay is not showing the thing it claims to show.
|
||||||
|
let at = |x: u32, y: u32| {
|
||||||
|
let p = ((y * w + x) * 4) as usize;
|
||||||
|
[pixels[p], pixels[p + 1], pixels[p + 2]]
|
||||||
|
};
|
||||||
|
assert_ne!(at(w / 2, h / 2), at(2, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The signature has to change when a mask's ids would mean something
|
||||||
|
/// different, and this is the case that actually happens: the same image
|
||||||
|
/// segmented at another proxy size.
|
||||||
|
#[test]
|
||||||
|
fn re_segmenting_at_another_size_invalidates_stored_ids() {
|
||||||
|
let Some(ctx) = context() else {
|
||||||
|
eprintln!("no adapter; skipping");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
const SIZE: u32 = 192;
|
||||||
|
let rgba = disc(SIZE);
|
||||||
|
let source = dr_gpu::DemosaicedImage::from_rgba8(&ctx, &rgba, SIZE, SIZE).expect("upload");
|
||||||
|
let rgb: Vec<f32> = rgba
|
||||||
|
.chunks_exact(4)
|
||||||
|
.flat_map(|p| [p[0] as f32 / 255.0, p[1] as f32 / 255.0, p[2] as f32 / 255.0])
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut coarse = Options {
|
||||||
|
semantic: false,
|
||||||
|
..Options::default()
|
||||||
|
};
|
||||||
|
coarse.segment.max_edge = 96;
|
||||||
|
|
||||||
|
let mut fine = coarse;
|
||||||
|
fine.segment.max_edge = 192;
|
||||||
|
|
||||||
|
let a = compute(&ctx, &source, &rgb, SIZE as usize, SIZE as usize, &coarse).expect("a");
|
||||||
|
let b = compute(&ctx, &source, &rgb, SIZE as usize, SIZE as usize, &fine).expect("b");
|
||||||
|
assert_ne!(
|
||||||
|
a.signature(),
|
||||||
|
b.signature(),
|
||||||
|
"ids from one proxy must not be read as ids from another"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run-to-run stability on one device, which is what lets a selection be
|
||||||
|
/// stored and reopened at all (M5).
|
||||||
|
#[test]
|
||||||
|
fn the_same_image_segments_identically_twice() {
|
||||||
|
let Some(ctx) = context() else {
|
||||||
|
eprintln!("no adapter; skipping");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
const SIZE: u32 = 128;
|
||||||
|
let rgba = disc(SIZE);
|
||||||
|
let source = dr_gpu::DemosaicedImage::from_rgba8(&ctx, &rgba, SIZE, SIZE).expect("upload");
|
||||||
|
let rgb: Vec<f32> = rgba
|
||||||
|
.chunks_exact(4)
|
||||||
|
.flat_map(|p| [p[0] as f32 / 255.0, p[1] as f32 / 255.0, p[2] as f32 / 255.0])
|
||||||
|
.collect();
|
||||||
|
let options = Options {
|
||||||
|
semantic: false,
|
||||||
|
..Options::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let a = compute(&ctx, &source, &rgb, SIZE as usize, SIZE as usize, &options).expect("a");
|
||||||
|
let b = compute(&ctx, &source, &rgb, SIZE as usize, SIZE as usize, &options).expect("b");
|
||||||
|
|
||||||
|
assert_eq!(a.signature(), b.signature());
|
||||||
|
assert_eq!(a.region_count(), b.region_count());
|
||||||
|
assert_eq!(a.regions_at(0.5, 0.5), b.regions_at(0.5, 0.5));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+74
-64
@@ -96,6 +96,10 @@ component MaskEntry inherits Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Caption {
|
Caption {
|
||||||
|
// Elided rather than wrapped: this sits beside two fixed
|
||||||
|
// targets in a row, and wrapping would give the rows of a
|
||||||
|
// stack different heights for no gain.
|
||||||
|
overflow: elide;
|
||||||
// Three states worth distinguishing, and each has a
|
// Three states worth distinguishing, and each has a
|
||||||
// different remedy: stale needs the segmentation re-run,
|
// different remedy: stale needs the segmentation re-run,
|
||||||
// unadjusted needs a slider moved, and the ordinary case
|
// unadjusted needs a slider moved, and the ordinary case
|
||||||
@@ -194,6 +198,13 @@ export component MaskPanel inherits Rectangle {
|
|||||||
|
|
||||||
background: Theme.surface;
|
background: Theme.surface;
|
||||||
|
|
||||||
|
// **Flat, deliberately.** An earlier version grouped each state into its
|
||||||
|
// own `if ...: VerticalLayout { ... }`. The nested layout under-reported
|
||||||
|
// its height, so the divider and the mask row below it were placed over
|
||||||
|
// the "Find regions" button — the sort of fault that is invisible in the
|
||||||
|
// source and obvious the moment anyone looks at the panel. Conditioning
|
||||||
|
// each child on its own keeps every element a direct child of one layout,
|
||||||
|
// which is the layout that measures them.
|
||||||
VerticalLayout {
|
VerticalLayout {
|
||||||
padding: Theme.gap;
|
padding: Theme.gap;
|
||||||
spacing: Theme.gap-sm;
|
spacing: Theme.gap-sm;
|
||||||
@@ -207,73 +218,70 @@ export component MaskPanel inherits Rectangle {
|
|||||||
|
|
||||||
if !root.enabled: Caption { text: "No image"; }
|
if !root.enabled: Caption { text: "No image"; }
|
||||||
|
|
||||||
// --- the region map ------------------------------------------------
|
// --- the region map ---------------------------------------------
|
||||||
//
|
//
|
||||||
// Segmentation is a thing the user starts. Half a second of watershed
|
// Segmentation is a thing the user starts. Half a second of watershed
|
||||||
// and inference is too long to spend on every photograph opened, and
|
// and inference is too long to spend on every photograph opened, and
|
||||||
// most edits never need one.
|
// most edits never need one.
|
||||||
if root.enabled && !root.segmented: VerticalLayout {
|
if root.enabled && !root.segmented: Caption {
|
||||||
|
text: "Find the regions in this photograph, so a mask can snap to them.";
|
||||||
|
// Wrapped, or this sentence's single-line width becomes the
|
||||||
|
// panel's minimum and levers the fixed 280px develop column open,
|
||||||
|
// taking every other panel's controls off the right edge with it.
|
||||||
|
wrap: word-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
if root.enabled && !root.segmented: Button {
|
||||||
|
text: root.segmenting ? "Finding regions…" : "Find regions";
|
||||||
|
enabled: !root.segmenting;
|
||||||
|
primary: true;
|
||||||
|
clicked => { root.segment(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// The overlay the whole map is judged by, and the picking mode that
|
||||||
|
// makes a click mean "select" instead of "pan".
|
||||||
|
if root.enabled && root.segmented: HorizontalLayout {
|
||||||
spacing: Theme.gap-sm;
|
spacing: Theme.gap-sm;
|
||||||
|
|
||||||
Caption {
|
Button {
|
||||||
text: "Find the regions in this photograph, so a mask can snap to them.";
|
text: "Overlay";
|
||||||
|
active: root.overlay;
|
||||||
|
clicked => { root.overlay-toggled(!root.overlay); }
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
text: root.segmenting ? "Finding regions…" : "Find regions";
|
text: "Select";
|
||||||
enabled: !root.segmenting;
|
active: root.picking;
|
||||||
primary: true;
|
clicked => { root.picking-toggled(!root.picking); }
|
||||||
clicked => { root.segment(); }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if root.enabled && root.segmented && root.picking: Caption {
|
||||||
|
text: "Click the photograph to select a region. Shift-click to add or remove.";
|
||||||
|
wrap: word-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Granularity, labelled by what it does rather than by its number:
|
||||||
|
// "detail" is what a photographer is choosing between, where "300
|
||||||
|
// regions" is an implementation detail they would have to learn.
|
||||||
|
if root.enabled && root.segmented: SliderRow {
|
||||||
|
label: "Detail";
|
||||||
|
value: root.level;
|
||||||
|
default-value: 300;
|
||||||
|
minimum: 8;
|
||||||
|
maximum: 2000;
|
||||||
|
changed(v) => { root.level-changed(v); }
|
||||||
|
reset => { root.level-changed(300); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- what the model found ----------------------------------------
|
||||||
|
if root.enabled && root.segmented && root.subjects.length > 0: Caption {
|
||||||
|
text: "Recognised";
|
||||||
|
}
|
||||||
|
|
||||||
if root.enabled && root.segmented: VerticalLayout {
|
if root.enabled && root.segmented: VerticalLayout {
|
||||||
spacing: Theme.gap-sm;
|
spacing: 0px;
|
||||||
|
for subject in root.subjects: subject-row := TouchArea {
|
||||||
HorizontalLayout {
|
|
||||||
spacing: Theme.gap-sm;
|
|
||||||
|
|
||||||
// The overlay the whole map is judged by. Without it the
|
|
||||||
// granularity control is a number with no visible meaning.
|
|
||||||
Button {
|
|
||||||
text: "Overlay";
|
|
||||||
active: root.overlay;
|
|
||||||
clicked => { root.overlay-toggled(!root.overlay); }
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
text: "Select";
|
|
||||||
active: root.picking;
|
|
||||||
clicked => { root.picking-toggled(!root.picking); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if root.picking: Caption {
|
|
||||||
text: "Click the photograph to select a region. Shift-click to add or remove.";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Granularity. Labelled by what it does rather than by its number:
|
|
||||||
// "detail" is what a photographer is choosing between, where "300
|
|
||||||
// regions" is an implementation detail they would have to learn.
|
|
||||||
SliderRow {
|
|
||||||
label: "Detail";
|
|
||||||
value: root.level;
|
|
||||||
default-value: 300;
|
|
||||||
minimum: 8;
|
|
||||||
maximum: 2000;
|
|
||||||
changed(v) => { root.level-changed(v); }
|
|
||||||
reset => { root.level-changed(300); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- what the model found -------------------------------------------
|
|
||||||
if root.enabled && root.segmented && root.subjects.length > 0: VerticalLayout {
|
|
||||||
spacing: 2px;
|
|
||||||
padding-top: Theme.gap-sm;
|
|
||||||
|
|
||||||
Caption { text: "Recognised"; }
|
|
||||||
|
|
||||||
for subject[i] in root.subjects: subject-row := TouchArea {
|
|
||||||
height: Theme.touch-target;
|
height: Theme.touch-target;
|
||||||
mouse-cursor: pointer;
|
mouse-cursor: pointer;
|
||||||
clicked => { root.add-subject(subject.index); }
|
clicked => { root.add-subject(subject.index); }
|
||||||
@@ -285,6 +293,7 @@ export component MaskPanel inherits Rectangle {
|
|||||||
text: subject.label;
|
text: subject.label;
|
||||||
emphasised: subject-row.has-hover;
|
emphasised: subject-row.has-hover;
|
||||||
horizontal-stretch: 1;
|
horizontal-stretch: 1;
|
||||||
|
overflow: elide;
|
||||||
}
|
}
|
||||||
Value { text: round(subject.score * 100) + "%"; }
|
Value { text: round(subject.score * 100) + "%"; }
|
||||||
}
|
}
|
||||||
@@ -296,15 +305,15 @@ export component MaskPanel inherits Rectangle {
|
|||||||
background: Theme.rule;
|
background: Theme.rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- the stack -------------------------------------------------------
|
// --- the stack -----------------------------------------------------
|
||||||
|
Caption { text: "Masks"; }
|
||||||
|
|
||||||
|
// Gradients need no segmentation, so they are offered whether or not
|
||||||
|
// one has been computed — a graduated filter over a sky is a local
|
||||||
|
// adjustment that never needed to know what a sky is.
|
||||||
HorizontalLayout {
|
HorizontalLayout {
|
||||||
spacing: Theme.gap-sm;
|
spacing: Theme.gap-sm;
|
||||||
|
|
||||||
Caption { text: "Masks"; horizontal-stretch: 1; }
|
|
||||||
|
|
||||||
// Gradients need no segmentation, so they are offered whether or
|
|
||||||
// not one has been computed — a graduated filter over a sky is a
|
|
||||||
// local adjustment that never needed to know what a sky is.
|
|
||||||
Button {
|
Button {
|
||||||
text: "Linear";
|
text: "Linear";
|
||||||
enabled: root.enabled;
|
enabled: root.enabled;
|
||||||
@@ -319,6 +328,7 @@ export component MaskPanel inherits Rectangle {
|
|||||||
|
|
||||||
if root.enabled && root.masks.length == 0: Caption {
|
if root.enabled && root.masks.length == 0: Caption {
|
||||||
text: "No local adjustments. Select a region, or add a gradient.";
|
text: "No local adjustments. Select a region, or add a gradient.";
|
||||||
|
wrap: word-wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
for mask in root.masks: MaskEntry {
|
for mask in root.masks: MaskEntry {
|
||||||
@@ -331,14 +341,14 @@ export component MaskPanel inherits Rectangle {
|
|||||||
opacity-changed(v) => { root.mask-opacity-changed(mask.id, v); }
|
opacity-changed(v) => { root.mask-opacity-changed(mask.id, v); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// The one thing the panel has to say about the adjust panel below
|
// The one thing this panel has to say about the adjust panel below it,
|
||||||
// it, because otherwise selecting a layer silently changes what those
|
// because otherwise selecting a layer silently changes what those
|
||||||
// sliders mean — the single most confusing thing a scoped panel can
|
// sliders mean — the most confusing thing a scoped panel can do.
|
||||||
// do.
|
|
||||||
if root.enabled && root.masks.length > 0: Caption {
|
if root.enabled && root.masks.length > 0: Caption {
|
||||||
text: root.editing-mask
|
text: root.editing-mask
|
||||||
? "The controls below adjust the selected mask."
|
? "The controls below adjust the selected mask."
|
||||||
: "The controls below adjust the whole photograph.";
|
: "The controls below adjust the whole photograph.";
|
||||||
|
wrap: word-wrap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user