Merge master into tablet-selection
Two real conflicts, both from work that landed either side of the same lines rather than against them. `lib.rs`: the settings controller was hoisted above the People screen's wiring, and Android's thumbnail-tier eviction registered itself at the same point. Independent, so both stay. `library.rs`: manual collection ordering and burst folding each added a clause to the same two queries. The scoped range read now carries both — the folding matters there for one step further on than it does in the grid, because a collapsed burst is one cell, so an ordinal counted over a list still holding every frame names a photograph several places away from the one the user pointed at. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,8 @@ import { LibraryGrid, LibraryCell, TimelineBar, PhotoRoll, KeywordRow, PersonChi
|
||||
import { Button, PanelHeading, Label, Value, Caption, Panel, EmptyState, ProgressBar, ActivityRow } from "widgets.slint";
|
||||
import { CollectionsPanel, CollectionRow, OfflinePrompt } from "collections.slint";
|
||||
import { HistogramPanel, HistogramView } from "histogram.slint";
|
||||
import { PresetSheet } from "presets.slint";
|
||||
import { FocusMarks, FocusPanel } from "peaking.slint";
|
||||
import { SettingsPage } from "settings.slint";
|
||||
import { ImportPage } from "import.slint";
|
||||
import { StatusBar, InfoPanel } from "develop.slint";
|
||||
@@ -70,6 +72,22 @@ export component AppWindow inherits Window {
|
||||
/// of a draft frame is a histogram of an image nobody is reading.
|
||||
in property <HistogramView> histogram;
|
||||
|
||||
/// TRACES: FR-CULL-3
|
||||
/// Focus peaking: the marks, whether they describe *this* frame, and the
|
||||
/// three things the photographer chose. All of them are Rust's, because
|
||||
/// the marks come from a compute pass — see `peaking.slint` for why
|
||||
/// `focus-overlay-ready` is a separate question from `peaking-on`.
|
||||
in property <image> focus-overlay;
|
||||
in property <bool> focus-overlay-ready: false;
|
||||
in property <bool> peaking-on: false;
|
||||
in property <bool> peaking-available: true;
|
||||
in property <int> peaking-sensitivity: 1;
|
||||
in property <int> peaking-colour: 0;
|
||||
|
||||
callback peaking-toggled(bool);
|
||||
callback peaking-sensitivity-picked(int);
|
||||
callback peaking-colour-picked(int);
|
||||
|
||||
// --- zoom, pan and crop (FR-DEV-4) ---
|
||||
//
|
||||
// Zoom is a *viewing* state, not an edit: it changes the resolution the
|
||||
@@ -585,6 +603,8 @@ export component AppWindow inherits Window {
|
||||
callback library-cell-rated(int, int);
|
||||
/// The trash target was clicked on one cell, by row.
|
||||
callback library-cell-trashed(int);
|
||||
/// The burst mark was clicked on one cell, by row (FR-CULL-5).
|
||||
callback library-burst-toggled(int);
|
||||
/// Move the grid selection to the trash — the `Delete` key.
|
||||
callback library-trash-selection();
|
||||
/// A judgement key was pressed, applying to the whole selection. One of
|
||||
@@ -661,6 +681,35 @@ export component AppWindow inherits Window {
|
||||
/// Apply the clipboard to every selected image in the grid.
|
||||
callback paste-settings-to-selection();
|
||||
|
||||
// --- named presets (FR-DEV-6) ---
|
||||
//
|
||||
// The saved half of the same requirement. On the window rather than in a
|
||||
// view for the reason the clipboard is: a preset is saved in develop,
|
||||
// where there is an edit to capture, and applied most often in the grid,
|
||||
// where there is a selection to apply it to.
|
||||
in-out property <bool> presets-open: false;
|
||||
in property <[string]> preset-names;
|
||||
/// Whether there is an edit in hand to save, set by whichever view opened
|
||||
/// the sheet. `in-out` because that is where the answer is known.
|
||||
in-out property <bool> preset-can-save: false;
|
||||
/// What applying would act on: 0 is the open photograph, higher is that
|
||||
/// many selected. Set at open, and read back by Rust when one is picked —
|
||||
/// so the action matches the count the user read on the way in.
|
||||
in-out property <int> preset-apply-count: 0;
|
||||
/// What saving would capture, from the routine the clipboard summary uses.
|
||||
in property <string> preset-capture-summary;
|
||||
/// Why the last name was refused, cleared by the next keystroke.
|
||||
in property <string> preset-name-error;
|
||||
callback save-preset(string);
|
||||
callback apply-preset(string);
|
||||
callback rename-preset(string, string);
|
||||
callback delete-preset(string);
|
||||
callback preset-name-edited(string);
|
||||
/// Raised as the sheet opens over an open photograph, so Rust can say what
|
||||
/// saving would capture. A property refreshed on every slider drag would
|
||||
/// be recomputing a string nobody is looking at.
|
||||
callback presets-opened();
|
||||
|
||||
// --- settings (FR-EXP-1, FR-EXP-3, FR-NC-6a) ---
|
||||
//
|
||||
// A page rather than an overlay, and the outermost of the view conditions
|
||||
@@ -1444,6 +1493,15 @@ in property <bool> panel-visible: true;
|
||||
paste-settings-to-selection => {
|
||||
root.paste-settings-to-selection();
|
||||
}
|
||||
// TRACES: FR-DEV-6
|
||||
// Opened with the selection's size, which is both what the
|
||||
// sheet says it would act on and what the apply handler
|
||||
// reads back to decide it means the batch.
|
||||
open-presets => {
|
||||
root.preset-apply-count = root.library-selected-count;
|
||||
root.preset-can-save = false;
|
||||
root.presets-open = true;
|
||||
}
|
||||
|
||||
// TRACES: FR-EXP-7
|
||||
exporting: root.library-exporting;
|
||||
@@ -1527,6 +1585,7 @@ in property <bool> panel-visible: true;
|
||||
|
||||
cell-rated(i, n) => { root.library-cell-rated(i, n); }
|
||||
cell-trashed(i) => { root.library-cell-trashed(i); }
|
||||
burst-toggled(i) => { root.library-burst-toggled(i); }
|
||||
trash-selection() => { root.library-trash-selection(); }
|
||||
// Derived from the sidebar's own selection rather than
|
||||
// mirrored in a second property: `-1` is already the sentinel
|
||||
@@ -1654,6 +1713,18 @@ in property <bool> panel-visible: true;
|
||||
image-rendering: ImageRendering.pixelated;
|
||||
}
|
||||
|
||||
// TRACES: FR-CULL-3
|
||||
// The focus marks, over the same fitted rect. See
|
||||
// `peaking.slint` for why they are a layer over the canvas
|
||||
// rather than a tint in it.
|
||||
if root.focus-overlay-ready && root.total > 0: FocusMarks {
|
||||
x: parent.shown-x;
|
||||
y: parent.shown-y;
|
||||
width: parent.shown-w;
|
||||
height: parent.shown-h;
|
||||
marks: root.focus-overlay;
|
||||
}
|
||||
|
||||
// Where the photograph actually sits inside this box.
|
||||
//
|
||||
// `image-fit: contain` letterboxes, and Slint does not report
|
||||
@@ -2187,6 +2258,26 @@ in property <bool> panel-visible: true;
|
||||
background: Theme.rule;
|
||||
}
|
||||
|
||||
// TRACES: FR-CULL-3
|
||||
// Under the histogram, because the two are the same
|
||||
// kind of thing: instruments that report on the
|
||||
// photograph rather than change it. Kept in every
|
||||
// mode for the same reason the histogram is.
|
||||
FocusPanel {
|
||||
available: root.peaking-available;
|
||||
showing: root.peaking-on;
|
||||
sensitivity: root.peaking-sensitivity;
|
||||
colour: root.peaking-colour;
|
||||
toggled(v) => { root.peaking-toggled(v); }
|
||||
sensitivity-picked(i) => { root.peaking-sensitivity-picked(i); }
|
||||
colour-picked(i) => { root.peaking-colour-picked(i); }
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
height: 1px;
|
||||
background: Theme.rule;
|
||||
}
|
||||
|
||||
// Framing above the colour work, matching how the edit is
|
||||
// made rather than how it is applied: the frame is decided
|
||||
// by eye first and the pipeline runs it last (see
|
||||
@@ -2240,6 +2331,15 @@ in property <bool> panel-visible: true;
|
||||
framing-withheld: root.settings-framing-withheld;
|
||||
copy => { root.copy-settings(); }
|
||||
paste => { root.paste-settings(); }
|
||||
// Opened with no count, which is what tells
|
||||
// the apply handler this means the open
|
||||
// photograph rather than a selection.
|
||||
open-presets => {
|
||||
root.preset-apply-count = 0;
|
||||
root.preset-can-save = root.adjust-enabled;
|
||||
root.presets-opened();
|
||||
root.presets-open = true;
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -2439,6 +2539,26 @@ in property <bool> panel-visible: true;
|
||||
// Below the load bar, above everything else: a download started from
|
||||
// here shows its progress in that bar, and the bar must not be the
|
||||
// thing the dialogue covers.
|
||||
// TRACES: FR-DEV-6
|
||||
// Over the shell rather than inside a view, because both views open
|
||||
// it — and because the develop column is 320px wide, which is not
|
||||
// enough to list presets and rename one in.
|
||||
if root.presets-open: PresetSheet {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
names: root.preset-names;
|
||||
can-save: root.preset-can-save;
|
||||
apply-count: root.preset-apply-count;
|
||||
capture-summary: root.preset-capture-summary;
|
||||
name-error: root.preset-name-error;
|
||||
save(name) => { root.save-preset(name); }
|
||||
apply(name) => { root.apply-preset(name); }
|
||||
rename(from, to) => { root.rename-preset(from, to); }
|
||||
remove(name) => { root.delete-preset(name); }
|
||||
name-edited(text) => { root.preset-name-edited(text); }
|
||||
dismiss => { root.presets-open = false; }
|
||||
}
|
||||
|
||||
OfflinePrompt {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
Reference in New Issue
Block a user