Link fifty gestures on the help sheet to the manual section that shows them

The sheet could now offer "See it", but no gesture said where to look.

Every GESTURE tag whose move the manual describes names that section:
the white-balance picker, zoom and pan, masks, undo and snapshots,
export, colour labels and ratings, selection, collections, the People
page, thumbnail size. Fifty of the fifty-one; the one left, putting a
single control back to its default, has no section and is too small to
earn one.

Three important gestures had nowhere to land, so the manual gains three
short sections, without pictures for now: Bursts (opening a folded
burst, choosing the frame it shows, and the eyes-open filter), Moving
between photographs (the roll, the arrows and A/D in develop) and
Copying settings (Copy, Paste, Paste to N, and choosing what a copy
carries). The page, the gesture book and docs/gestures.md are
regenerated from them.
This commit is contained in:
2026-09-24 23:25:37 -04:00
parent 7591738c73
commit 150e53e878
12 changed files with 276 additions and 128 deletions
+1
View File
@@ -167,6 +167,7 @@ component GroupHeading inherits Rectangle {
// One click is one sample and one step to undo; the sliders
// stay, because a sampled neutral is where the decision
// starts rather than where it ends.
// manual: white-balance-from-the-photograph
//
// TRACES: FR-DEV-3 | NFR-A11Y-2
// The eyedropper, built exactly as the reset beside it is: a word, a
+15
View File
@@ -1788,6 +1788,7 @@ in property <bool> panel-visible: true;
// is the way to everything in between. Past
// 1:1 the pixels are shown as they are, square
// and unsmoothed; below it, filtered.
// manual: looking-closer
//
// TRACES: FR-UI-4
// Pinch to zoom. The wheel gesture below is the desktop's
@@ -1882,6 +1883,7 @@ in property <bool> panel-visible: true;
// beside the photograph, and that reads as
// a rendering fault rather than as the end
// of the picture.
// manual: looking-closer
moved => {
if (self.pressed && root.zoomed) {
// Fractions of the *visible* area, which is what
@@ -1968,6 +1970,7 @@ in property <bool> panel-visible: true;
// ways. The whole stroke is one step in the
// history, so taking a mark back costs one
// press however long it took to make.
// manual: local-adjustments
//
// TRACES: FR-DEV-19b
//
@@ -2200,6 +2203,7 @@ in property <bool> panel-visible: true;
// frame of a gesture. The list is there
// because arriving six steps back costs
// what arriving from one does.
// manual: history-snapshots-presets
//
// GESTURE: Do it again after taking it back
// where: Develop
@@ -2208,6 +2212,7 @@ in property <bool> panel-visible: true;
// pointer: Click it, or press Redo in the
// History header
// keys: Ctrl+Shift+Z
// manual: history-snapshots-presets
//
// Ctrl+Z and Ctrl+Shift+Z (FR-DEV-5). Both cases
// of the letter, because the logical key that
@@ -2245,6 +2250,7 @@ in property <bool> panel-visible: true;
// action from. The shortcut is an
// accelerator for a control that is on
// screen either way.
// manual: copying-settings
//
// GESTURE: Paste the settings onto this photograph
// where: Develop
@@ -2256,6 +2262,7 @@ in property <bool> panel-visible: true;
// whether the crop is coming with it —
// which the shortcut cannot say. Both
// paste the same scope.
// manual: copying-settings
//
// TRACES: FR-DEV-6
// The desktop accelerators for the Copy and Paste
@@ -2274,6 +2281,7 @@ in property <bool> panel-visible: true;
// leaving each frame's crop and
// rotation alone, and that is a choice
// to make at the moment of copying.
// manual: copying-settings
//
// Shift first: the logical key is "C" under shift,
// which the plain copy below would otherwise take.
@@ -2303,6 +2311,7 @@ in property <bool> panel-visible: true;
// chord is Lightroom's and darktable's,
// kept so hands that learned it there
// need not learn it again.
// manual: export
//
// GESTURE: Choose how to export, then export
// where: Develop
@@ -2314,6 +2323,7 @@ in property <bool> panel-visible: true;
// What is chosen there is kept, so it
// is also what the next Ctrl+Shift+E
// uses.
// manual: export
//
// TRACES: FR-UI-5 | FR-EXP-7
// Both cases of the letter, as for Z: holding
@@ -2342,6 +2352,7 @@ in property <bool> panel-visible: true;
// and no key can be assigned to one of
// them by name. Stepping is the binding
// that survives a node being added.
// manual: developing-a-photograph
//
// TRACES: FR-DEV-3a | FR-UI-5
// -1 is "everything" and is part of the cycle
@@ -2385,6 +2396,7 @@ in property <bool> panel-visible: true;
// the photograph is drawn as its own
// pixels, each a hard-edged square,
// rather than smoothed into a blur.
// manual: looking-closer
//
// TRACES: FR-UI-4 | FR-UI-5
// Fit and 1:1 from the keyboard, so inspecting
@@ -2432,6 +2444,7 @@ in property <bool> panel-visible: true;
// stepping through a folder is one
// hand's work. The bar names the label
// in words beside its mark.
// manual: rating-and-flagging
//
// TRACES: FR-CAT-5 | FR-UI-5 | NFR-A11Y-3
// Only with a library: a file named on the command
@@ -2460,6 +2473,7 @@ in property <bool> panel-visible: true;
// steps along the roll while the right stays on
// the mouse. Unmodified only: Ctrl+D and Ctrl+A
// are not this.
// manual: moving-between-photographs
if (event.text == Key.RightArrow || event.text == " "
|| (!event.modifiers.control
&& (event.text == "d" || event.text == "D"))) {
@@ -2590,6 +2604,7 @@ in property <bool> panel-visible: true;
// takes no history step, so checking
// whether a frame is overcooked costs
// nothing to undo afterwards.
// manual: light
//
// TRACES: FR-DEV-7 | FR-DEV-3b | NFR-A11Y-2
// The unedited original, for as long as it is held.
+4
View File
@@ -342,6 +342,7 @@ component TreeRow inherits Rectangle {
// something, and it is what every mobile list already uses to
// pick a row up. The row lifts the moment it fires, so the
// gesture says it has been understood before anything moves.
// manual: collections
//
// GESTURE: Act on a collection — rename, nest, un-nest, delete
// where: Collections sidebar
@@ -352,6 +353,7 @@ component TreeRow inherits Rectangle {
// uses. One menu for everything done to a row, because there is
// one hold per row: while the hold opened the offline question
// by itself, nothing else the tree can do had a touch route.
// manual: collections
//
// GESTURE: Take a collection back out of the one it is nested in
// where: Collections sidebar
@@ -365,6 +367,7 @@ component TreeRow inherits Rectangle {
// library — and wrong for a collection, which has a top level
// to be returned to. Without it a collection dragged into
// another was in there permanently.
// manual: collections
//
// GESTURE: Rename a collection
// where: Collections sidebar
@@ -373,6 +376,7 @@ component TreeRow inherits Rectangle {
// why: Double-click is what a file manager and a Lightroom panel use
// for the same thing, so it needs no discovering — but nothing
// on screen says so, which is what the menu item is for.
// manual: collections
touch := TouchArea {
// Disabled while the field is up, so a click landing on the row rather
// than inside the input does not re-select the collection out from
+2
View File
@@ -98,6 +98,7 @@ component SnapshotItem inherits Rectangle {
// I liked twenty minutes ago" is how a choice between two
// treatments is actually made. It takes no history step
// and changes nothing; letting go puts the edit back.
// manual: history-snapshots-presets
//
// TRACES: FR-DEV-7
eye := TouchArea {
@@ -314,6 +315,7 @@ export component HistoryPanel inherits Rectangle {
// of the edit, so it survives a restart and reaches the
// other device. Pressing a snapshot puts the photograph
// back to it, as one step that undo takes back whole.
// manual: history-snapshots-presets
if Develop.enabled: HorizontalLayout {
spacing: Theme.gap-sm;
+4
View File
@@ -193,6 +193,7 @@ component FaceCell inherits Rectangle {
// children, and on the same person a decade apart, so
// splitting is as prominent as merging. A tool that can
// only merge makes its own errors permanent.
// manual: people
TouchArea {
clicked => { root.toggle-pick(); }
}
@@ -218,6 +219,7 @@ component FaceCell inherits Rectangle {
// suggestion they sit beside, and `IconButton`'s fallback would
// announce them as "check" and "cross" — two icon names that say
// nothing about which person is being ruled on.
// manual: people
if !face.confirmed: IconButton {
icon: "check";
label: "Confirm this face";
@@ -639,6 +641,7 @@ export component IdentityScreen inherits Rectangle {
// why: This is the point of having identified anybody.
// Without it the screen is a filing cabinet with no
// drawer handles.
// manual: people
if root.selected-person >= 0: Button {
text: "Show photos";
clicked => { root.show-photos(root.selected-person, false); }
@@ -678,6 +681,7 @@ export component IdentityScreen inherits Rectangle {
// answers for this library without writing
// anything; names, confirmations and the groups you
// have set aside are kept whatever the dials say.
// manual: people
Button {
text: "Grouping…";
active: root.grouping-open;
+20
View File
@@ -1634,6 +1634,7 @@ export component LibraryGrid inherits Rectangle {
// select a second photograph — the first tap would open it.
// The hold is the fast way in and the button is the one that
// can be found.
// manual: selecting-several
//
// GESTURE: Add or remove one photograph
// where: Library grid
@@ -1642,12 +1643,14 @@ export component LibraryGrid inherits Rectangle {
// why: While selecting, a tap never opens. That is the whole point
// of the mode: one meaning per gesture at a time. Press Done to
// get tap-to-open back.
// manual: selecting-several
//
// GESTURE: Leave selecting
// where: Library grid
// touch: Press Done in the header
// pointer: Press Done in the header
// keys: Escape
// manual: selecting-several
in property <bool> select-mode: false;
callback toggle-select-mode();
@@ -1683,6 +1686,7 @@ export component LibraryGrid inherits Rectangle {
// there the drag cannot be lost to a scroll. A mouse never
// waits: the cursor is precise enough that a sideways drag is
// unambiguous from the first pixel.
// manual: collections
in-out property <int> held-row: -1;
/// TRACES: FR-CAT-5
// --- reordering a manual collection (FR-CAT-7) --------------------------
@@ -1749,6 +1753,7 @@ export component LibraryGrid inherits Rectangle {
// can scroll between the two taps — the ranges that hurt on a
// tablet are longer than a screenful, which is exactly where a
// finger sweep runs out.
// manual: selecting-several
property <bool> ranging: false;
// A range armed against nothing has no anchor to extend from, and the strip
@@ -2461,6 +2466,7 @@ export component LibraryGrid inherits Rectangle {
// drops frames where the chosen people are caught
// blinking, and leaves sunglasses and eyes it could
// not read alone.
// manual: bursts
if root.filter-people.length > 0: FilterChip {
icon: "eye";
label: "Eyes open";
@@ -2492,6 +2498,7 @@ export component LibraryGrid inherits Rectangle {
// intersection. The tray is where both terms and the
// choice between them live, because a filter belongs
// on the filter bar.
// manual: people
FilterChip {
icon: root.people-tray ? "chevron-down" : "chevron-right";
label: "People";
@@ -2610,6 +2617,7 @@ export component LibraryGrid inherits Rectangle {
// why: Each chip is the label's mark and its name, so
// the one you want is found by reading it; tap
// the lit chip again to show every label.
// manual: rating-and-flagging
//
// TRACES: FR-CAT-6 | NFR-A11Y-3
// One chip per colour label, each the cell's own mark and the
@@ -3077,6 +3085,7 @@ export component LibraryGrid inherits Rectangle {
// plain chord opens them beside an Export
// button and the shifted one skips straight to
// exporting.
// manual: export
//
// TRACES: FR-EXP-7 | FR-UI-5
// Before the bare keys below: a chord must not also be read
@@ -3096,6 +3105,7 @@ export component LibraryGrid inherits Rectangle {
// selection bar
// pointer: Select them, then "Paste to N"
// keys: Ctrl+V
// manual: copying-settings
//
// TRACES: FR-DEV-6 | FR-UI-5
// Silent with nothing copied, as the button is disabled.
@@ -3123,6 +3133,7 @@ export component LibraryGrid inherits Rectangle {
// with a ceiling — the twos and threes still
// to be decided — is the keyboard's alone, and
// the bar says so in words while it holds.
// manual: rating-and-flagging
//
// Held rather than typed in sequence, so nothing waits
// to find out whether a second digit is coming: every
@@ -3176,6 +3187,7 @@ export component LibraryGrid inherits Rectangle {
// mark carries its label's initial, so the
// label is read without telling the colours
// apart.
// manual: rating-and-flagging
//
// TRACES: FR-CAT-5 | FR-UI-5 | NFR-A11Y-3
// After the F chord above, which has returned for its own
@@ -3348,6 +3360,7 @@ export component LibraryGrid inherits Rectangle {
// why: There is no wheel on a tablet, so without the
// pinch the cell size could only be changed by a
// control a finger cannot reach.
// manual: getting-about
grid-pinch := ScaleRotateGestureHandler {
width: 100%;
height: parent.viewport-height;
@@ -3549,6 +3562,7 @@ export component LibraryGrid inherits Rectangle {
// why: The selection is what the drag carries, which is
// why selecting several is worth the mode: forty
// photographs file in one gesture.
// manual: collections
for cell[i] in root.cells: DragArea {
// Cells are positioned at their **absolute** place in the
// library, not their index in the loaded window: the window
@@ -3846,6 +3860,7 @@ export component LibraryGrid inherits Rectangle {
// finger to dwell 120 ms instead, and that
// rejected ordinary taps — a real tap is
// often quicker than a brush.
// manual: developing-a-photograph
property <int> down-finger: -1;
property <bool> click-pending: false;
@@ -3963,6 +3978,7 @@ export component LibraryGrid inherits Rectangle {
// why: A star has to take the press without it
// also reaching the cell, or every rating
// throws the user into develop.
// manual: rating-and-flagging
//
// --- the rating strip, INSIDE the cell's hit area ---
//
@@ -4104,6 +4120,7 @@ export component LibraryGrid inherits Rectangle {
// they are open and side by side, which is
// the one moment the alternatives are on
// screen to be compared.
// manual: bursts
//
// Drawn on every frame of an open group and on none of
// a folded one. Folded, the single cell showing *is*
@@ -4769,6 +4786,7 @@ export component LibraryGrid inherits Rectangle {
// why: Distinct from Done, which leaves the mode
// entirely. Clearing keeps it, so the next
// selection can start straight away.
// manual: selecting-several
if !root.ranging && root.selected-count > 0: Button {
text: "Clear";
y: (parent.height - self.height) / 2;
@@ -4788,6 +4806,7 @@ export component LibraryGrid inherits Rectangle {
// taps otherwise, and "all of them, except those
// three" is a far more common shape than the taps it
// took to say it.
// manual: selecting-several
if !root.ranging && root.selected-count > 0: Button {
text: "Select all";
y: (parent.height - self.height) / 2;
@@ -4928,6 +4947,7 @@ export component LibraryGrid inherits Rectangle {
// three collections and never which. This is the sheet
// that names them, and the only way out of one the grid
// is not currently scoped to.
// manual: collections
if !root.ranging && root.selected-count > 0: Button {
text: "Collections…";
y: (parent.height - self.height) / 2;
+4
View File
@@ -221,6 +221,7 @@ component MaskEntry inherits Rectangle {
// keys: H, for the selected layer
// history step, unlike holding "Before" — the layer
// really is off until it is switched back on.
// manual: local-adjustments
//
// The eye. Disabling a layer is the A/B a local edit constantly
// wants, so it is one press away rather than inside the row.
@@ -289,6 +290,7 @@ component MaskEntry inherits Rectangle {
// its. Nothing about the edit changes: this is how
// the photograph is looked at, and takes no history
// step.
// manual: local-adjustments
//
// TRACES: FR-DEV-19c
eye := TouchArea {
@@ -371,6 +373,7 @@ component MaskEntry inherits Rectangle {
// a photographer flips a join while looking at
// the picture, not at the panel: add, take
// away, keep only where both agree, and round.
// manual: local-adjustments
//
// TRACES: FR-DEV-19a
join := TouchArea {
@@ -413,6 +416,7 @@ component MaskEntry inherits Rectangle {
// answers that and loses it. The same ring the
// layer wears, one row down, because it is the
// same question about a smaller thing.
// manual: local-adjustments
//
// TRACES: FR-DEV-19a
part-eye := TouchArea {