Open presets from a menu at the foot of the tool rail
Presets were a "Presets…" button in develop's top bar that opened a sheet over the photograph, so applying one was two clicks with the picture covered. They are now an entry pinned to the bottom of the tool rail, apart from the tools because a preset arms nothing, and it opens a menu beside the rail: the same sectioned rows the sheet lists, one click to apply to the open photograph. The menu's last row, "Save or manage…", opens the sheet, which keeps saving, renaming, reverting and importing, since those take a name or a path. The menu is a PopupWindow for the film list's reasons, with the list in a clipped box of its own; the Flickable alone let its last row draw over the manage row. Choosing from it zeroes preset-apply-count before applying, since the grid may have left its selection count there. The manual says where presets are now and gains a picture of the open menu. The scenes reach the sheet through the menu and aim the manage row from the rail's entry, as the film list's rows are aimed, because the automation reports a popup's elements in the popup's coordinates.
This commit is contained in:
+29
-29
File diff suppressed because one or more lines are too long
+22
-22
@@ -39,7 +39,7 @@ The list is longer than it is tall, so a way to walk it that cannot be lost to t
|
||||
|
||||
Anchored on the fingers' midpoint, and on the pointer, so the gesture reads as magnifying the picture rather than sliding it about. Double-tap is the way to an exact 1:1; this is the way to everything in between. Past 1:1 the pixels are shown as they are, square and unsmoothed; below it, filtered.
|
||||
|
||||
<sub>`ui/dr-ui/ui/app.slint:1961`</sub>
|
||||
<sub>`ui/dr-ui/ui/app.slint:1972`</sub>
|
||||
|
||||
### Move a magnified photograph about
|
||||
|
||||
@@ -50,7 +50,7 @@ Anchored on the fingers' midpoint, and on the pointer, so the gesture reads as m
|
||||
|
||||
Only once there is something outside the viewport to reach, which is why the cursor becomes a hand exactly then. The view is clamped to the frame: panning past the edge would show undefined area beside the photograph, and that reads as a rendering fault rather than as the end of the picture.
|
||||
|
||||
<sub>`ui/dr-ui/ui/app.slint:2057`</sub>
|
||||
<sub>`ui/dr-ui/ui/app.slint:2068`</sub>
|
||||
|
||||
### Paint a mask by hand
|
||||
|
||||
@@ -60,7 +60,7 @@ Only once there is something outside the viewport to reach, which is why the cur
|
||||
|
||||
A model's mask stops inside a shoulder and leaks into the hair, and no single edge control fixes two errors that go opposite ways. The whole stroke is one step in the history, so taking a mark back costs one press however long it took to make.
|
||||
|
||||
<sub>`ui/dr-ui/ui/app.slint:2148`</sub>
|
||||
<sub>`ui/dr-ui/ui/app.slint:2159`</sub>
|
||||
|
||||
### Open this list
|
||||
|
||||
@@ -70,7 +70,7 @@ A model's mask stops inside a shoulder and leaks into the hair, and no single ed
|
||||
|
||||
Most of the keys are develop's, and a reference that could only be opened from the grid had to be looked up before opening the photograph they were wanted for.
|
||||
|
||||
<sub>`ui/dr-ui/ui/app.slint:2374`</sub>
|
||||
<sub>`ui/dr-ui/ui/app.slint:2385`</sub>
|
||||
|
||||
### Take back the last change
|
||||
|
||||
@@ -81,7 +81,7 @@ Most of the keys are develop's, and a reference that could only be opened from t
|
||||
|
||||
A whole drag is one step, so undo takes back a decision rather than a frame of a gesture. The list is there because arriving six steps back costs what arriving from one does.
|
||||
|
||||
<sub>`ui/dr-ui/ui/app.slint:2404`</sub>
|
||||
<sub>`ui/dr-ui/ui/app.slint:2415`</sub>
|
||||
|
||||
### Do it again after taking it back
|
||||
|
||||
@@ -90,7 +90,7 @@ A whole drag is one step, so undo takes back a decision rather than a frame of a
|
||||
- **Keyboard** — `Ctrl+Shift+Z`, or `Ctrl+Y`
|
||||
- **See it** — [in the manual](manual/README.md#history-snapshots-presets)
|
||||
|
||||
<sub>`ui/dr-ui/ui/app.slint:2418`</sub>
|
||||
<sub>`ui/dr-ui/ui/app.slint:2429`</sub>
|
||||
|
||||
### Remove a repair
|
||||
|
||||
@@ -98,7 +98,7 @@ A whole drag is one step, so undo takes back a decision rather than a frame of a
|
||||
- **Pointer** — Click it, then Delete Repair
|
||||
- **Keyboard** — `Delete` or `Backspace`, while repairing
|
||||
|
||||
<sub>`ui/dr-ui/ui/app.slint:2438`</sub>
|
||||
<sub>`ui/dr-ui/ui/app.slint:2449`</sub>
|
||||
|
||||
### Copy the settings from this photograph
|
||||
|
||||
@@ -109,7 +109,7 @@ A whole drag is one step, so undo takes back a decision rather than a frame of a
|
||||
|
||||
The button is the copy that has to work: a tablet has no modifier key to hold and no menu bar to hang the action from. The shortcut is an accelerator for a control that is on screen either way.
|
||||
|
||||
<sub>`ui/dr-ui/ui/app.slint:2457`</sub>
|
||||
<sub>`ui/dr-ui/ui/app.slint:2468`</sub>
|
||||
|
||||
### Paste the settings onto this photograph
|
||||
|
||||
@@ -120,7 +120,7 @@ The button is the copy that has to work: a tablet has no modifier key to hold an
|
||||
|
||||
The button names what would be pasted — "3 adjustments", and whether the crop is coming with it — which the shortcut cannot say. Both paste the same scope.
|
||||
|
||||
<sub>`ui/dr-ui/ui/app.slint:2470`</sub>
|
||||
<sub>`ui/dr-ui/ui/app.slint:2481`</sub>
|
||||
|
||||
### Choose which kinds of edit a copy carries
|
||||
|
||||
@@ -131,7 +131,7 @@ The button names what would be pasted — "3 adjustments", and whether the crop
|
||||
|
||||
Lightroom's Copy Settings. Pasting a look across a shoot usually means leaving each frame's crop and rotation alone, and that is a choice to make at the moment of copying.
|
||||
|
||||
<sub>`ui/dr-ui/ui/app.slint:2488`</sub>
|
||||
<sub>`ui/dr-ui/ui/app.slint:2499`</sub>
|
||||
|
||||
### Export this photograph as the last one was
|
||||
|
||||
@@ -142,7 +142,7 @@ Lightroom's Copy Settings. Pasting a look across a shoot usually means leaving e
|
||||
|
||||
Every export runs on the defaults in Settings, so "as the last one was" is what the button already does. The chord is Lightroom's and darktable's, kept so hands that learned it there need not learn it again.
|
||||
|
||||
<sub>`ui/dr-ui/ui/app.slint:2513`</sub>
|
||||
<sub>`ui/dr-ui/ui/app.slint:2524`</sub>
|
||||
|
||||
### Choose how to export, then export
|
||||
|
||||
@@ -153,7 +153,7 @@ Every export runs on the defaults in Settings, so "as the last one was" is what
|
||||
|
||||
The export sheet is the export defaults alone with an Export button. What is chosen there is kept, so it is also what the next Ctrl+Shift+E uses.
|
||||
|
||||
<sub>`ui/dr-ui/ui/app.slint:2526`</sub>
|
||||
<sub>`ui/dr-ui/ui/app.slint:2537`</sub>
|
||||
|
||||
### Keep a crop that leaves a mask outside
|
||||
|
||||
@@ -161,7 +161,7 @@ The export sheet is the export defaults alone with an Export button. What is cho
|
||||
- **Pointer** — Press "Keep crop" on the notice, or "Undo crop" to take it back
|
||||
- **Keyboard** — `Enter` keeps it; `Ctrl+Z` takes the crop back, like any other step
|
||||
|
||||
<sub>`ui/dr-ui/ui/app.slint:2591`</sub>
|
||||
<sub>`ui/dr-ui/ui/app.slint:2602`</sub>
|
||||
|
||||
### Go back to the grid
|
||||
|
||||
@@ -171,7 +171,7 @@ The export sheet is the export defaults alone with an Export button. What is cho
|
||||
|
||||
Lightroom's key for the grid. Escape gets there too, but a step at a time — out of a mode, then out of a zoom — where this goes straight back.
|
||||
|
||||
<sub>`ui/dr-ui/ui/app.slint:2608`</sub>
|
||||
<sub>`ui/dr-ui/ui/app.slint:2619`</sub>
|
||||
|
||||
### Nudge the control last moved
|
||||
|
||||
@@ -181,7 +181,7 @@ Lightroom's key for the grid. Escape gets there too, but a step at a time — ou
|
||||
|
||||
Lightroom's keys for the selected slider. There is no focus ring on a slider here, so "selected" is the last one moved — the same control `R` puts back — which covers the framing sliders, perspective included, as well as the adjustments.
|
||||
|
||||
<sub>`ui/dr-ui/ui/app.slint:2637`</sub>
|
||||
<sub>`ui/dr-ui/ui/app.slint:2648`</sub>
|
||||
|
||||
### Change which group of adjustments is on screen
|
||||
|
||||
@@ -192,7 +192,7 @@ Lightroom's keys for the selected slider. There is no focus ring on a slider her
|
||||
|
||||
The groups are whatever the operation set declares itself to be about, so there are as many as the pipeline has and no key can be assigned to one of them by name. Stepping is the binding that survives a node being added.
|
||||
|
||||
<sub>`ui/dr-ui/ui/app.slint:2665`</sub>
|
||||
<sub>`ui/dr-ui/ui/app.slint:2676`</sub>
|
||||
|
||||
### Look at the photograph at 1:1
|
||||
|
||||
@@ -203,7 +203,7 @@ The groups are whatever the operation set declares itself to be about, so there
|
||||
|
||||
Noise reduction and capture sharpening are judgements about single pixels, and a fitted view averages several of the file's into each one on screen — so the frame looks softer than it is and the correction goes too far. The point and the magnification survive opening the next photograph, which is what makes checking the same eye across forty portraits forty keystrokes rather than forty pans. From 1:1 on the photograph is drawn as its own pixels, each a hard-edged square, rather than smoothed into a blur.
|
||||
|
||||
<sub>`ui/dr-ui/ui/app.slint:2701`</sub>
|
||||
<sub>`ui/dr-ui/ui/app.slint:2712`</sub>
|
||||
|
||||
### Rate this photograph
|
||||
|
||||
@@ -211,7 +211,7 @@ Noise reduction and capture sharpening are judgements about single pixels, and a
|
||||
- **Pointer** — Click a star in the top bar
|
||||
- **Keyboard** — `0`–`5`
|
||||
|
||||
<sub>`ui/dr-ui/ui/app.slint:2758`</sub>
|
||||
<sub>`ui/dr-ui/ui/app.slint:2769`</sub>
|
||||
|
||||
### Pick or reject this photograph
|
||||
|
||||
@@ -221,7 +221,7 @@ Noise reduction and capture sharpening are judgements about single pixels, and a
|
||||
|
||||
The grid's keys, on the photograph that is open (FR-UI-5, 2026-09-19). Judging here does not move on to the next frame: that belongs to culling, and in develop the photograph in front of you is the one being worked on.
|
||||
|
||||
<sub>`ui/dr-ui/ui/app.slint:2764`</sub>
|
||||
<sub>`ui/dr-ui/ui/app.slint:2775`</sub>
|
||||
|
||||
### Give this photograph a colour label
|
||||
|
||||
@@ -232,7 +232,7 @@ The grid's keys, on the photograph that is open (FR-UI-5, 2026-09-19). Judging h
|
||||
|
||||
The grid's keys, on the photograph that is open, so labelling while stepping through a folder is one hand's work. The bar names the label in words beside its mark.
|
||||
|
||||
<sub>`ui/dr-ui/ui/app.slint:2794`</sub>
|
||||
<sub>`ui/dr-ui/ui/app.slint:2805`</sub>
|
||||
|
||||
### Move to the next or previous photograph
|
||||
|
||||
@@ -243,7 +243,7 @@ The grid's keys, on the photograph that is open, so labelling while stepping thr
|
||||
|
||||
The edit on screen is saved on the way out, so stepping through a folder is as much a departure as going back to the grid and loses nothing. A and D as well as the arrows, so the left hand steps along the roll while the right stays on the mouse.
|
||||
|
||||
<sub>`ui/dr-ui/ui/app.slint:2819`</sub>
|
||||
<sub>`ui/dr-ui/ui/app.slint:2830`</sub>
|
||||
|
||||
### See the photograph before you edited it
|
||||
|
||||
@@ -254,7 +254,7 @@ The edit on screen is saved on the way out, so stepping through a folder is as m
|
||||
|
||||
Held rather than toggled, and no split screen: a split halves the working image on the tablet the column was sized for, and the comparison photographers describe making is a flick back and forth. It takes no history step, so checking whether a frame is overcooked costs nothing to undo afterwards.
|
||||
|
||||
<sub>`ui/dr-ui/ui/app.slint:2949`</sub>
|
||||
<sub>`ui/dr-ui/ui/app.slint:2960`</sub>
|
||||
|
||||
### Put one control back to its default
|
||||
|
||||
|
||||
+10
-5
@@ -287,11 +287,14 @@ a gradient over the sky whose `Print Exposure` burns it in.
|
||||
### History, snapshots, presets
|
||||
|
||||
Every change is a step; `Undo` and the History panel walk them. `Snapshot`
|
||||
keeps the current state under a name. `Presets…` saves the settings to
|
||||
apply elsewhere, and imports Lightroom presets — `Folder…` for a folder of
|
||||
them, `.xmp file…` for one.
|
||||
keeps the current state under a name. `Presets`, at the foot of the tool
|
||||
rail on the left, opens a menu of presets beside the photograph; choosing
|
||||
one applies it. The menu's last row, `Save or manage…`, opens the presets
|
||||
sheet, which saves the settings to apply elsewhere, renames and deletes
|
||||
them, and imports Lightroom presets — `Folder…` for a folder of them,
|
||||
`.xmp file…` for one.
|
||||
|
||||
The sheet lists your own presets first, then the ones DarkRoom ships —
|
||||
The menu and the sheet list your own presets first, then the ones DarkRoom ships —
|
||||
Essentials, Skies, and colour, cinema and black-and-white film, one measured stock
|
||||
each. A shipped preset is a look: it changes what it names and leaves the
|
||||
photograph's own corrections alone, as an imported Lightroom preset does.
|
||||
@@ -300,6 +303,8 @@ applies, marked *changed*; `Revert` brings the shipped one back, and renaming
|
||||
yours makes it one of your own. A film preset carries its stock: choosing one
|
||||
sets the `Film` chooser and leaves the rest of the edit where it was.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
@@ -310,7 +315,7 @@ sets the `Film` chooser and leaves the rest of the edit where it was.
|
||||
or Ctrl+V, puts them on another, and says what it would paste — how many
|
||||
adjustments, and whether the crop comes too. In the grid, `Paste to N` on the
|
||||
selection bar pastes onto every photograph selected. Which kinds of edit a
|
||||
copy carries is chosen in `Presets…`, or with Ctrl+Shift+C: a look carried
|
||||
copy carries is chosen in the presets sheet, or with Ctrl+Shift+C: a look carried
|
||||
across a shoot usually leaves each frame's own crop alone.
|
||||
|
||||
## Merging a panorama
|
||||
|
||||
@@ -342,10 +342,13 @@ a gradient over the sky whose <code>Print Exposure</code> burns it in.</p>
|
||||
<figure><img loading="lazy" src="media/film-local.gif" alt="Kodak Ektar 100 on the whole frame, a gradient turned to cover the sky, its Print Exposure raised to burn the sky in, then holding Before"><figcaption>Kodak Ektar 100 on the whole frame, a gradient turned to cover the sky, its Print Exposure raised to burn the sky in, then holding Before</figcaption></figure>
|
||||
<h3 id="history-snapshots-presets">History, snapshots, presets</h3>
|
||||
<p>Every change is a step; <code>Undo</code> and the History panel walk them. <code>Snapshot</code>
|
||||
keeps the current state under a name. <code>Presets…</code> saves the settings to
|
||||
apply elsewhere, and imports Lightroom presets — <code>Folder…</code> for a folder of
|
||||
them, <code>.xmp file…</code> for one.</p>
|
||||
<p>The sheet lists your own presets first, then the ones DarkRoom ships —
|
||||
keeps the current state under a name. <code>Presets</code>, at the foot of the tool
|
||||
rail on the left, opens a menu of presets beside the photograph; choosing
|
||||
one applies it. The menu's last row, <code>Save or manage…</code>, opens the presets
|
||||
sheet, which saves the settings to apply elsewhere, renames and deletes
|
||||
them, and imports Lightroom presets — <code>Folder…</code> for a folder of them,
|
||||
<code>.xmp file…</code> for one.</p>
|
||||
<p>The menu and the sheet list your own presets first, then the ones DarkRoom ships —
|
||||
Essentials, Skies, and colour, cinema and black-and-white film, one measured stock
|
||||
each. A shipped preset is a look: it changes what it names and leaves the
|
||||
photograph's own corrections alone, as an imported Lightroom preset does.
|
||||
@@ -353,6 +356,7 @@ Saving under a shipped preset's name makes your version the one that name
|
||||
applies, marked <em>changed</em>; <code>Revert</code> brings the shipped one back, and renaming
|
||||
yours makes it one of your own. A film preset carries its stock: choosing one
|
||||
sets the <code>Film</code> chooser and leaves the rest of the edit where it was.</p>
|
||||
<figure><img loading="lazy" src="media/presets-menu.png" alt="The presets menu open beside the tool rail, over the photograph"><figcaption>The presets menu open beside the tool rail, over the photograph</figcaption></figure>
|
||||
<figure><img loading="lazy" src="media/presets.png" alt="The presets sheet: a name for the current edit, the shipped Essentials, importing, and what an apply carries"><figcaption>The presets sheet: a name for the current edit, the shipped Essentials, importing, and what an apply carries</figcaption></figure>
|
||||
<figure><img loading="lazy" src="media/presets-film.gif" alt="Scrolling down the shipped presets to the black-and-white films, applying Ilford HP5 Plus, then holding Before"><figcaption>Scrolling down the shipped presets to the black-and-white films, applying Ilford HP5 Plus, then holding Before</figcaption></figure>
|
||||
<h3 id="copying-settings">Copying settings</h3>
|
||||
@@ -360,7 +364,7 @@ sets the <code>Film</code> chooser and leaves the rest of the edit where it was.
|
||||
or Ctrl+V, puts them on another, and says what it would paste — how many
|
||||
adjustments, and whether the crop comes too. In the grid, <code>Paste to N</code> on the
|
||||
selection bar pastes onto every photograph selected. Which kinds of edit a
|
||||
copy carries is chosen in <code>Presets…</code>, or with Ctrl+Shift+C: a look carried
|
||||
copy carries is chosen in the presets sheet, or with Ctrl+Shift+C: a look carried
|
||||
across a shoot usually leaves each frame's own crop alone.</p>
|
||||
<h2 id="merging-a-panorama">Merging a panorama</h2>
|
||||
<p>Select the frames, then <code>Merge to panorama</code> from the selection bar. The
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
+30
-5
@@ -1148,11 +1148,35 @@ def film_reach():
|
||||
undo_all()
|
||||
|
||||
|
||||
@scene(media=['presets.png'], sources=DEVELOP_SRC + ['ui/dr-ui/ui/presets.slint', 'ui/dr-ui/src/presets.rs'])
|
||||
PRESET_ROW = 32 # `menu-row-height` in toolrail.slint
|
||||
|
||||
|
||||
def presets_menu_open():
|
||||
"""The presets menu at the foot of the tool rail, open."""
|
||||
dr.click_on('Presets@Button')
|
||||
dr.wait_for('Save or manage…@Button', 5)
|
||||
|
||||
|
||||
def presets_manage():
|
||||
""""Save or manage…", the menu's last row, pressed to open the sheet.
|
||||
|
||||
Aimed from the rail's entry rather than by name, as the film list's rows
|
||||
are: the automation reports a popup's elements in the popup's own
|
||||
coordinates. The menu opens beside the entry with its foot level with
|
||||
the entry's, and the row is the last `PRESET_ROW` of it."""
|
||||
_, _, x1, y1 = dr.rect('Presets@Button')
|
||||
dr.click(x1 + 100, y1 - PRESET_ROW // 2)
|
||||
dr.wait_for('CARRIES@Text', 5)
|
||||
|
||||
|
||||
@scene(media=['presets-menu.png', 'presets.png'],
|
||||
sources=DEVELOP_SRC + ['ui/dr-ui/ui/presets.slint', 'ui/dr-ui/src/presets.rs'])
|
||||
def presets():
|
||||
at_develop()
|
||||
dr.click_on('Presets…@Button')
|
||||
dr.wait_for('CARRIES@Text', 5)
|
||||
presets_menu_open()
|
||||
pause(1.0)
|
||||
shot('presets-menu')
|
||||
presets_manage()
|
||||
pause(1.5)
|
||||
shot('presets')
|
||||
dr.click_on('Done@Button#-1')
|
||||
@@ -1170,8 +1194,9 @@ def presets_film():
|
||||
at_develop()
|
||||
rec('presets-film')
|
||||
pause(0.4)
|
||||
dr.click_on('Presets…@Button')
|
||||
dr.wait_for('CARRIES@Text', 5)
|
||||
presets_menu_open()
|
||||
pause(0.8)
|
||||
presets_manage()
|
||||
pause(1.5)
|
||||
x, y = dr.centre('Crisp detail@Button')
|
||||
for _ in range(80): # a notch at a time, so the film shows the sections pass
|
||||
|
||||
@@ -1000,8 +1000,8 @@ pub fn wire_named(
|
||||
|
||||
// --- opening the sheet over the open photograph -----------------------
|
||||
//
|
||||
// The develop column's "Presets…" button, and everything opening the sheet
|
||||
// from there means. It used to be four lines inside the panel's
|
||||
// "Save or manage…" in the tool rail's presets menu, and everything
|
||||
// opening the sheet from there means. It used to be four lines inside the panel's
|
||||
// instantiation in `app.slint`, which is exactly the sort of behaviour a
|
||||
// second drawing of that panel would have had to copy; `Transfer` is a
|
||||
// global and a global cannot bind the window's own state, so it lands
|
||||
|
||||
@@ -1785,6 +1785,17 @@ in property <bool> panel-visible: true;
|
||||
tabs: Adjustments.tabs;
|
||||
active-tab: Adjustments.active-tab;
|
||||
group-picked(i) => { Adjustments.tab-picked(i); }
|
||||
|
||||
// TRACES: FR-DEV-6
|
||||
// The rail's presets menu applies to the photograph in
|
||||
// front of it, so the count the apply handler reads is
|
||||
// set to say so — the grid may have left its own there.
|
||||
presets: root.preset-rows;
|
||||
preset-picked(name) => {
|
||||
root.preset-apply-count = 0;
|
||||
root.apply-preset(name);
|
||||
}
|
||||
manage-presets => { Transfer.open-presets(); }
|
||||
}
|
||||
|
||||
// The canvas: compute output composited directly. No CPU
|
||||
|
||||
@@ -100,7 +100,7 @@ export component StatusBar inherits Rectangle {
|
||||
viewport-width: max(self.width, strip.preferred-width);
|
||||
|
||||
// Related controls sit closer together than unrelated ones: Pick and
|
||||
// Reject, Undo and Redo, Copy, Paste and Presets, Help and Settings are
|
||||
// Reject, Undo and Redo, Copy and Paste, Help and Settings are
|
||||
// each a group at `gap-sm`, with `gap` between groups. It reads as the
|
||||
// pairs it is, and it is also what keeps Settings on screen at 1600
|
||||
// pixels wide once Help joined the strip.
|
||||
@@ -285,13 +285,9 @@ export component StatusBar inherits Rectangle {
|
||||
clicked => { Transfer.paste(); }
|
||||
}
|
||||
|
||||
// The saved half: this edit, kept under a name.
|
||||
Button {
|
||||
text: "Presets…";
|
||||
enabled: Develop.enabled;
|
||||
y: (parent.height - self.height) / 2;
|
||||
clicked => { Transfer.open-presets(); }
|
||||
}
|
||||
// The saved half — this edit, kept under a name — is at the foot
|
||||
// of the tool rail now (`toolrail.slint`), as a menu beside the
|
||||
// photograph rather than a sheet over it.
|
||||
}
|
||||
|
||||
// Show or hide the develop column. On a tablet the panel is 280px of a
|
||||
|
||||
@@ -386,4 +386,17 @@ export component Icon inherits Rectangle {
|
||||
commands: "M 4.6 14.8 A 5 5 0 1 0 14.6 14.8 A 5 5 0 1 0 4.6 14.8 Z "
|
||||
+ "M 11.8 9 A 4 4 0 1 0 19.8 9 A 4 4 0 1 0 11.8 9 Z";
|
||||
}
|
||||
|
||||
// TRACES: FR-DEV-6
|
||||
// Presets: a stack of prints, the front one whole and two edges behind
|
||||
// it. Not a tool — it arms nothing on the canvas — so it is the one
|
||||
// drawing in the rail with no frame broken or marked: a saved edit is a
|
||||
// finished photograph, several times over.
|
||||
if root.name == "presets": Ink {
|
||||
stroke: root.ink;
|
||||
stroke-width: root.weight;
|
||||
commands: "M 3.4 9.4 L 16.6 9.4 L 16.6 20.6 L 3.4 20.6 Z "
|
||||
+ "M 6.2 6.4 L 19.4 6.4 L 19.4 17.6 "
|
||||
+ "M 9 3.4 L 20.6 3.4 L 20.6 14.6";
|
||||
}
|
||||
}
|
||||
|
||||
+229
-1
@@ -53,6 +53,8 @@
|
||||
import { Theme } from "theme.slint";
|
||||
import { Icon } from "icons.slint";
|
||||
import { ViewMode } from "session.slint";
|
||||
import { PresetRow, PresetOrigin } from "presets.slint";
|
||||
import { PanelHeading, Label, ScrollBar } from "widgets.slint";
|
||||
|
||||
// One tool. A struct rather than four parallel arrays so a row cannot be
|
||||
// half-added — the compiler will not let a new entry omit its icon.
|
||||
@@ -117,6 +119,25 @@ export component ToolRail inherits Rectangle {
|
||||
/// reason to want to.
|
||||
callback group-picked(int);
|
||||
|
||||
/// TRACES: FR-DEV-6
|
||||
/// The presets, sectioned — the same rows the preset sheet lists — and
|
||||
/// what choosing one from the rail's menu asks for.
|
||||
///
|
||||
/// **A menu at the foot of the rail, not a tool in its table.** A tool
|
||||
/// arms something on the canvas and stays lit while it is held; a preset
|
||||
/// is applied and is over. Drawing it as a fifth tool would light a tile
|
||||
/// for a state that does not exist. It sits apart, pinned to the bottom
|
||||
/// edge so a rail long with groups cannot scroll it away, and it opens a
|
||||
/// list beside the photograph it is about to change — one click to apply,
|
||||
/// where the sheet in the strip was two and covered the picture.
|
||||
///
|
||||
/// Saving, renaming and importing stay in the sheet (`presets.slint`):
|
||||
/// they take a name or a path, and a menu is the wrong place to type.
|
||||
/// The menu's last row opens it.
|
||||
in property <[PresetRow]> presets;
|
||||
callback preset-picked(string);
|
||||
callback manage-presets();
|
||||
|
||||
/// The groups this rail actually draws.
|
||||
///
|
||||
/// A conditional model rather than an `if` wrapped around the repeater:
|
||||
@@ -191,6 +212,16 @@ export component ToolRail inherits Rectangle {
|
||||
// construction — a tool is `rail-entry-height` and a group is a touch
|
||||
// target, both stated a few lines below — so this is exact rather than an
|
||||
// estimate, and it depends on nothing that depends on it.
|
||||
// The presets entry's share of the rail, taken off the bottom of the
|
||||
// scroller above it rather than added to its content, so it never
|
||||
// scrolls.
|
||||
private property <length> foot-height: Theme.rail-entry-height + 1px;
|
||||
|
||||
// One row of the presets menu. Shorter than a touch target for the reason
|
||||
// the film list gives: a row's neighbours are other rows.
|
||||
private property <length> menu-row-height: 32px;
|
||||
private property <length> menu-width: 240px;
|
||||
|
||||
private property <length> content-height:
|
||||
Theme.gap-sm
|
||||
+ root.tools.length * Theme.rail-entry-height
|
||||
@@ -200,7 +231,7 @@ export component ToolRail inherits Rectangle {
|
||||
|
||||
Flickable {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
height: parent.height - root.foot-height;
|
||||
viewport-width: self.width;
|
||||
viewport-height: max(self.height, root.content-height);
|
||||
|
||||
@@ -407,6 +438,203 @@ export component ToolRail inherits Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
// TRACES: FR-DEV-6
|
||||
// The presets, pinned to the foot of the rail. A rule above it says it is
|
||||
// not one of the tools, and it lights only while its menu is open.
|
||||
Rectangle {
|
||||
x: Theme.gap-sm;
|
||||
y: parent.height - root.foot-height;
|
||||
width: parent.width - 2 * Theme.gap-sm;
|
||||
height: 1px;
|
||||
background: Theme.rule;
|
||||
}
|
||||
|
||||
presets-entry := TouchArea {
|
||||
y: parent.height - Theme.rail-entry-height;
|
||||
height: Theme.rail-entry-height;
|
||||
mouse-cursor: pointer;
|
||||
clicked => { preset-menu.show(); }
|
||||
|
||||
accessible-role: button;
|
||||
accessible-label: "Presets";
|
||||
accessible-action-default => { preset-menu.show(); }
|
||||
|
||||
property <bool> lit: preset-menu.is-open;
|
||||
|
||||
Rectangle {
|
||||
x: Theme.gap-sm / 2;
|
||||
width: parent.width - Theme.gap-sm;
|
||||
height: parent.height - 2px;
|
||||
y: 1px;
|
||||
border-radius: Theme.radius;
|
||||
background: presets-entry.lit || presets-entry.pressed
|
||||
? Theme.pressed
|
||||
: (presets-entry.has-hover ? Theme.hover : transparent);
|
||||
}
|
||||
|
||||
VerticalLayout {
|
||||
alignment: center;
|
||||
spacing: 3px;
|
||||
|
||||
HorizontalLayout {
|
||||
alignment: center;
|
||||
Icon {
|
||||
name: "presets";
|
||||
size: 20px;
|
||||
ink: presets-entry.lit || presets-entry.has-hover ? Theme.ink : Theme.ink-dim;
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Presets";
|
||||
font-size: Theme.text-sm;
|
||||
color: presets-entry.lit || presets-entry.has-hover ? Theme.ink : Theme.ink-faint;
|
||||
horizontal-alignment: center;
|
||||
overflow: elide;
|
||||
}
|
||||
}
|
||||
|
||||
// Beside the rail, its foot level with the entry's, so it grows up
|
||||
// over the photograph from where it was opened. Held to the rail's
|
||||
// height, which is the frame's: a long list scrolls rather than
|
||||
// running off the top of the window.
|
||||
//
|
||||
// A PopupWindow for the film list's reasons (`adjust.slint`): it is
|
||||
// its own tree, so it scrolls by wheel and drag whatever is under it,
|
||||
// and it closes on a choice, on Escape, or on a press outside it.
|
||||
preset-menu := PopupWindow {
|
||||
x: parent.width;
|
||||
y: parent.height - self.height;
|
||||
width: root.menu-width;
|
||||
height: min(
|
||||
(root.presets.length + 1) * root.menu-row-height + 1px,
|
||||
root.height - Theme.gap);
|
||||
close-policy: PopupClosePolicy.close-on-click-outside;
|
||||
|
||||
Rectangle {
|
||||
background: Theme.surface;
|
||||
border-radius: Theme.radius;
|
||||
border-width: 1px;
|
||||
border-color: Theme.rule;
|
||||
clip: true;
|
||||
|
||||
// The list, clipped by a box of its own: the Flickable alone
|
||||
// let its last row draw over "Save or manage…" below it.
|
||||
Rectangle {
|
||||
x: 0px;
|
||||
y: 0px;
|
||||
width: parent.width;
|
||||
height: parent.height - root.menu-row-height - 1px;
|
||||
clip: true;
|
||||
|
||||
// Counted, not measured, for the reason `content-height`
|
||||
// above gives: every row is `menu-row-height`.
|
||||
menu-flick := Flickable {
|
||||
width: parent.width;
|
||||
height: parent.height;
|
||||
viewport-width: self.width;
|
||||
viewport-height: root.presets.length * root.menu-row-height;
|
||||
|
||||
for entry[i] in root.presets: Rectangle {
|
||||
y: i * root.menu-row-height;
|
||||
width: parent.width;
|
||||
height: root.menu-row-height;
|
||||
|
||||
if entry.heading != "": PanelHeading {
|
||||
x: Theme.gap;
|
||||
width: parent.width - 2 * Theme.gap;
|
||||
height: parent.height;
|
||||
text: entry.heading;
|
||||
vertical-alignment: bottom;
|
||||
}
|
||||
|
||||
if entry.heading == "": row := TouchArea {
|
||||
mouse-cursor: pointer;
|
||||
clicked => {
|
||||
root.preset-picked(entry.name);
|
||||
preset-menu.close();
|
||||
}
|
||||
accessible-role: button;
|
||||
accessible-label: entry.name;
|
||||
accessible-action-default => {
|
||||
root.preset-picked(entry.name);
|
||||
preset-menu.close();
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
border-radius: Theme.radius;
|
||||
background: row.pressed ? Theme.pressed
|
||||
: (row.has-hover ? Theme.hover : transparent);
|
||||
|
||||
HorizontalLayout {
|
||||
padding-left: Theme.gap;
|
||||
padding-right: Theme.gap;
|
||||
Label {
|
||||
text: entry.origin == PresetOrigin.changed
|
||||
? entry.name + " · changed"
|
||||
: entry.name;
|
||||
emphasised: row.has-hover;
|
||||
vertical-alignment: center;
|
||||
overflow: elide;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ScrollBar {
|
||||
x: parent.width - self.width;
|
||||
y: 0px;
|
||||
height: menu-flick.height;
|
||||
viewport-y <=> menu-flick.viewport-y;
|
||||
viewport-height: menu-flick.viewport-height;
|
||||
visible-height: menu-flick.height;
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
y: menu-flick.height;
|
||||
height: 1px;
|
||||
background: Theme.rule;
|
||||
}
|
||||
|
||||
// Last, next to where the pointer came from: saving the edit
|
||||
// in hand is the other thing someone opening this wants.
|
||||
manage := TouchArea {
|
||||
y: parent.height - root.menu-row-height;
|
||||
height: root.menu-row-height;
|
||||
mouse-cursor: pointer;
|
||||
clicked => {
|
||||
preset-menu.close();
|
||||
root.manage-presets();
|
||||
}
|
||||
accessible-role: button;
|
||||
accessible-label: "Save or manage…";
|
||||
accessible-action-default => {
|
||||
preset-menu.close();
|
||||
root.manage-presets();
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
background: manage.pressed ? Theme.pressed
|
||||
: (manage.has-hover ? Theme.hover : transparent);
|
||||
|
||||
HorizontalLayout {
|
||||
padding-left: Theme.gap;
|
||||
padding-right: Theme.gap;
|
||||
Label {
|
||||
text: "Save or manage…";
|
||||
emphasised: manage.has-hover;
|
||||
vertical-alignment: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The rail's own edge. Drawn here rather than by whatever contains it, so
|
||||
// the rail is a complete thing wherever it is put — and on the right,
|
||||
// where it meets the canvas.
|
||||
|
||||
Reference in New Issue
Block a user