Move copy, paste and presets into the develop top bar

They sat in the develop column under a "SETTINGS" heading, which read as
application settings, and went away with the panel toggle and in the
mask and spot modes. The strip is where undo already is for the same
reason: these act on the whole edit, not on any one panel.

The paste button still names what it would apply. The TransferPanel
component is gone; the Transfer global and its Rust wiring are
unchanged.
This commit is contained in:
2026-09-22 21:37:31 -04:00
parent aee355fada
commit 9ebaa15099
7 changed files with 83 additions and 115 deletions
File diff suppressed because one or more lines are too long
+2 -1
View File
@@ -684,7 +684,8 @@ three columns of equal width side by side, each its own scroll:
with them because it is not in their column.
2. **Sliders** — `GroupStrip` above `AdjustPanel`, exactly as in the column.
With a group selected this is one screen of sliders; with All it scrolls.
3. **The mode's panels** — `ComposePanel` and `TransferPanel` in photo mode,
3. **The mode's panels** — `ComposePanel` in photo mode (copy and paste
moved to the top bar, 2026-09-22),
`SpotPanel` in repair, `MaskPanel` in local. Empty otherwise, which is
a signal of its own about which mode the view is in (§1.1).
+10 -10
View File
@@ -65,18 +65,18 @@ A whole drag is one step, so undo takes back a decision rather than a frame of a
### Copy the settings from this photograph
- **Touch** — Press Copy in the Settings panel
- **Pointer** — Press Copy in the Settings panel
- **Touch** — Press Copy in the top bar
- **Pointer** — Press Copy in the top bar
- **Keyboard** — Ctrl+C
The panel is the copy that has to work: a tablet has no modifier key to hold and no menu bar to hang the action from. The shortcut is an accelerator for a control that is on screen either way.
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:2206`</sub>
### Paste the settings onto this photograph
- **Touch** — Press Paste in the Settings panel
- **Pointer** — Press Paste in the Settings panel
- **Touch** — Press Paste in the top bar
- **Pointer** — Press Paste in the top bar
- **Keyboard** — Ctrl+V
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.
@@ -91,7 +91,7 @@ The button names what would be pasted — "3 adjustments", and whether the crop
The groups are whatever the operation set declares itself to be about, so there are as many as the pipeline has and no key can be assigned to one of them by name. Stepping is the binding that survives a node being added.
<sub>`ui/dr-ui/ui/app.slint:2246`</sub>
<sub>`ui/dr-ui/ui/app.slint:2245`</sub>
### Look at the photograph at 1:1
@@ -101,7 +101,7 @@ The groups are whatever the operation set declares itself to be about, so there
Noise reduction and capture sharpening are judgements about single pixels, and a fitted view averages several of the file's into each one on screen — so the frame looks softer than it is and the correction goes too far. The point and the magnification survive opening the next photograph, which is what makes checking the same eye across forty portraits forty keystrokes rather than forty pans.
<sub>`ui/dr-ui/ui/app.slint:2281`</sub>
<sub>`ui/dr-ui/ui/app.slint:2280`</sub>
### Move to the next or previous photograph
@@ -111,7 +111,7 @@ Noise reduction and capture sharpening are judgements about single pixels, and a
The edit on screen is saved on the way out, so stepping through a folder is as much a departure as going back to the grid and loses nothing.
<sub>`ui/dr-ui/ui/app.slint:2333`</sub>
<sub>`ui/dr-ui/ui/app.slint:2332`</sub>
### See the photograph before you edited it
@@ -121,7 +121,7 @@ The edit on screen is saved on the way out, so stepping through a folder is as m
Held rather than toggled, and no split screen: a split halves the working image on the tablet the column was sized for, and the comparison photographers describe making is a flick back and forth. It takes no history step, so checking whether a frame is overcooked costs nothing to undo afterwards.
<sub>`ui/dr-ui/ui/app.slint:2457`</sub>
<sub>`ui/dr-ui/ui/app.slint:2456`</sub>
### Put one control back to its default
@@ -390,4 +390,4 @@ A scoped grid of two hundred frames is two hundred taps otherwise, and "all of t
The badge on a cell says a photograph is filed in three collections and never which. This is the sheet that names them, and the only way out of one the grid is not currently scoped to.
<sub>`ui/dr-ui/ui/library.slint:4595`</sub>
<sub>`ui/dr-ui/ui/library.slint:4594`</sub>
+4 -4
View File
@@ -67,15 +67,15 @@ pub const GESTURES: &[Gesture] = &[
Gesture {
title: "Copy the settings from this photograph",
section: "Develop",
touch: "Press Copy in the Settings panel",
pointer: "Press Copy in the Settings panel",
touch: "Press Copy in the top bar",
pointer: "Press Copy in the top bar",
keys: "Ctrl+C",
},
Gesture {
title: "Paste the settings onto this photograph",
section: "Develop",
touch: "Press Paste in the Settings panel",
pointer: "Press Paste in the Settings panel",
touch: "Press Paste in the top bar",
pointer: "Press Paste in the top bar",
keys: "Ctrl+V",
},
Gesture {
-58
View File
@@ -886,64 +886,6 @@ export global Transfer {
callback open-presets();
}
// TRACES: FR-DEV-6
// Copying this photograph's settings, and pasting settings onto it.
//
// Buttons rather than a keyboard shortcut *alone*, because this has to work on
// a tablet where there is no modifier key to hold and no menu bar to hang the
// action from. The desktop shortcuts exist as well, wired in Rust; they are an
// accelerator for a control that is on screen either way, which is what keeps
// the feature discoverable on both platforms.
//
// The paste button carries what would be pasted rather than the bare word.
// "Paste" alone asks the user to remember what they copied and, crucially,
// whether the crop is coming with it — a question the label answers by
// naming the count the *current* scope would apply.
export component TransferPanel inherits VerticalLayout {
padding: Theme.gap;
spacing: Theme.gap-sm;
HorizontalLayout {
PanelHeading { text: "SETTINGS"; }
Rectangle { horizontal-stretch: 1; }
}
HorizontalLayout {
spacing: Theme.gap-sm;
Button {
text: "Copy";
enabled: Develop.enabled;
horizontal-stretch: 1;
clicked => { Transfer.copy(); }
}
Button {
text: "Paste";
// Enabled on `armed` rather than on the summary being non-empty,
// so pasting a neutral copy — which clears this image — stays
// available. Still needs an image to paste *onto*.
enabled: Develop.enabled && Transfer.armed;
horizontal-stretch: 1;
clicked => { Transfer.paste(); }
}
}
// TRACES: FR-DEV-6
// The saved half. On its own row rather than a third of the one above,
// because copy and paste are a pair — one arms the other — and a button
// that does neither sitting between them would read as part of that pair.
Button {
text: "Presets…";
enabled: Develop.enabled;
clicked => { Transfer.open-presets(); }
}
if Transfer.armed: Caption {
text: Transfer.summary + (Transfer.framing-withheld ? " · crop not included" : "");
}
}
/// TRACES: FR-DEV-3
/// The generated controls: what they show, what they are pointed at, and what
/// pressing one means.
+8 -21
View File
@@ -1,6 +1,6 @@
import { Theme } from "theme.slint";
import { Develop, ViewMode } from "session.slint";
import { AdjustPanel, Adjustments, ComposePanel, Framing, GroupStrip, ParamRow, Transfer, TransferPanel } from "adjust.slint";
import { AdjustPanel, Adjustments, ComposePanel, Framing, GroupStrip, ParamRow, Transfer } from "adjust.slint";
import { CategoryRow, GradientHandle, GradientHandles, HandleRole, MaskPanel, MaskRow, Masking, SubjectRow } from "masks.slint";
import { Repair, SpotHandle, SpotHandles, SpotPanel, SpotRole } from "spots.slint";
import { CropOverlay } from "crop.slint";
@@ -2205,10 +2205,10 @@ in property <bool> panel-visible: true;
}
// GESTURE: Copy the settings from this photograph
// where: Develop
// touch: Press Copy in the Settings panel
// pointer: Press Copy in the Settings panel
// touch: Press Copy in the top bar
// pointer: Press Copy in the top bar
// keys: Ctrl+C
// why: The panel is the copy that has to
// why: 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
@@ -2217,8 +2217,8 @@ in property <bool> panel-visible: true;
//
// GESTURE: Paste the settings onto this photograph
// where: Develop
// touch: Press Paste in the Settings panel
// pointer: Press Paste in the Settings panel
// touch: Press Paste in the top bar
// pointer: Press Paste in the top bar
// keys: Ctrl+V
// why: The button names what would be
// pasted — "3 adjustments", and
@@ -2227,9 +2227,8 @@ in property <bool> panel-visible: true;
// paste the same scope.
//
// TRACES: FR-DEV-6
// The desktop accelerators for the two buttons in
// the Settings panel, which until now the panel's
// own comment claimed existed and nothing bound.
// The desktop accelerators for the Copy and Paste
// buttons in the top bar.
// Guarded on `settings-armed` for the reason the
// button is: a paste with nothing copied is not a
// clear, it is a keystroke that should do nothing.
@@ -2741,18 +2740,6 @@ in property <bool> panel-visible: true;
// `dr_pipeline::framing` on the coordinate order).
if !Develop.local-mode && !Develop.repairing: ComposePanel { }
if !Develop.local-mode && !Develop.repairing: Rectangle {
height: 1px;
background: Theme.rule;
}
// Between the framing and the colour work, because it
// acts on both: a paste is about the whole edit, and
// burying it under thirty sliders would put the one
// control that operates on all of them below all of
// them.
if !Develop.local-mode && !Develop.repairing: TransferPanel { }
Rectangle {
height: 1px;
background: Theme.rule;
+38
View File
@@ -8,6 +8,8 @@
// front of it.
import { Theme } from "theme.slint";
import { Develop } from "session.slint";
import { Transfer } from "adjust.slint";
import { Button, PanelHeading, Label, Value, Caption, Panel } from "widgets.slint";
// Status strip — surfaces the GPU backend and adapter, which matters during
@@ -160,6 +162,42 @@ export component StatusBar inherits Rectangle {
clicked => { root.redo(); }
}
// TRACES: FR-DEV-6
// Copy and paste, in the strip beside undo for the reason undo is
// here: they act on the whole edit, not on any one panel, and the
// column can be put away. They sat in the column under a "SETTINGS"
// heading, which read as application settings and hid them behind a
// scroll and behind the panel toggle.
//
// The paste button names what would be pasted — "3 adjustments", and
// whether the crop is staying behind — because "Paste" alone asks the
// user to remember what they copied.
Button {
text: "Copy";
enabled: Develop.enabled;
y: (parent.height - self.height) / 2;
clicked => { Transfer.copy(); }
}
// Enabled on `armed` rather than on a non-empty summary, so pasting a
// neutral copy — which clears this image — stays available.
Button {
text: !Transfer.armed ? "Paste"
: "Paste " + Transfer.summary
+ (Transfer.framing-withheld ? ", no crop" : "");
enabled: Develop.enabled && Transfer.armed;
y: (parent.height - self.height) / 2;
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(); }
}
// Show or hide the develop column. On a tablet the panel is 280px of a
// screen that is mostly photograph, and the whole point of opening an
// image is to look at it — so being able to put the instruments away