Wire the develop panels through globals, so a second copy is one line
Every panel in the develop column declared its inputs and its callbacks and had `app.slint` bind each one to a property or a callback on the window root. That is fine while a panel is drawn once. N9 draws them a second time, in the portrait dock, and the wiring is what would have to be copied: `MaskPanel` alone ran to forty lines of forwarding, and a callback added to one copy and not the other compiles, renders, and simply does nothing on the layout nobody was looking at. So the wiring moved to Slint globals. A panel reads the global and calls the global; Rust hooks the global instead of the window; and the instantiation in the column is now the panel's name and a pair of braces — every one of the ten children of the column, with no property that differs by placement left to supply. There is a global per panel family rather than one for all of them, and the reason is an import cycle. Each panel's model struct — `ParamRow`, `MaskRow`, `HistogramView` — is declared in the panel's own file, so a single global holding `[MaskRow]` and `[ParamRow]` would have to live in a file importing `masks.slint` and `adjust.slint` while both imported the global back, which Slint rejects. Breaking that needs six model declarations relocated, which is a change to the data model and not to the plumbing this is about. A global beside the panel it serves also lets each name drop the prefix it was carrying only because the window root is one flat namespace: `root.spot-radius` is `Repair.radius`, and `root.peaking-on` is `Peaking.showing`. `session.slint` is new and holds the two facts every family needs and none of them owns: whether there is an open photograph to edit, and which mode the view is in, with the three readings of the mode derived once instead of at each of the dozen places that tested one. `ViewMode` moves there from `adjust.slint`, where it was only ever a lodger. Nothing on screen changes. What is not here: the tool rail and the status strip still take their properties at the instantiation, because they are drawn once and N9 does not copy them; the preset sheet's own state stays on the window, because the library grid opens the same sheet and a global cannot bind the window's state — which is why `Transfer.open-presets` is handled in `presets.rs`, beside the summary it already had to compute.
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
// What the develop view is doing, and whether there is anything to do it to.
|
||||
//
|
||||
// **Why the develop panels have globals at all.** Every panel in the develop
|
||||
// column used to declare its inputs and its callbacks and have `app.slint`
|
||||
// bind each one to a property or a callback on the window root. That is fine
|
||||
// while a panel is drawn once. `ui-navigation.md` N9 draws them a second time,
|
||||
// in the portrait dock, and forty lines of hand-written forwarding copied into
|
||||
// a second composition is the kind of duplication that drifts silently: a
|
||||
// callback added to one copy and not the other compiles, renders, and simply
|
||||
// does nothing on the layout nobody was looking at.
|
||||
//
|
||||
// So the wiring moved to globals. A panel reads the global and calls the
|
||||
// global; Rust hooks the global instead of the window; and a second
|
||||
// instantiation is the panel's name and a pair of braces.
|
||||
//
|
||||
// **Why there is more than one of them.** The obvious shape is a single
|
||||
// `Develop` global carrying all of it. Slint rejects cyclic imports, and each
|
||||
// panel's model struct — `ParamRow`, `MaskRow`, `HistogramView` — is declared
|
||||
// in the panel's own file. One global holding `[MaskRow]` and `[ParamRow]`
|
||||
// would therefore have to live in a file importing `masks.slint` and
|
||||
// `adjust.slint`, both of which would import the global back. Breaking that
|
||||
// needs the six model declarations relocated, which is a change to the data
|
||||
// model rather than to the plumbing this is about.
|
||||
//
|
||||
// A global per panel family instead, each declared in the file of the panel it
|
||||
// serves: `Adjustments`, `Framing` and `Transfer` in `adjust.slint`, `Masking`
|
||||
// in `masks.slint`, `Repair` in `spots.slint`, `Peaking` in `peaking.slint`,
|
||||
// `Levels` in `histogram.slint`, `Capture` in `develop.slint`, `Steps` in
|
||||
// `history.slint`. That also lets each name drop the prefix it was carrying
|
||||
// only because the window root is one flat namespace: `root.spot-radius` is
|
||||
// `Repair.radius`, and `root.peaking-on` is `Peaking.showing`.
|
||||
//
|
||||
// This file holds what is left: the two facts every one of those families
|
||||
// needs and none of them owns. It imports nothing, which is what lets every
|
||||
// panel file import it.
|
||||
|
||||
/// Which mode the develop view is in.
|
||||
///
|
||||
/// `crop` was a bare `bool` on the window and local masking was a panel with
|
||||
/// two toggles, so nothing stopped both being on at once — and nothing on
|
||||
/// screen said which of them the canvas and the column were obeying. One value
|
||||
/// with three states cannot be in two of them, which is the whole reason this
|
||||
/// is an enum rather than a tidier pair of flags.
|
||||
export enum ViewMode {
|
||||
/// The whole photograph. Sliders are global, the canvas pans and zooms.
|
||||
photo,
|
||||
/// The crop overlay is up and the canvas shows the uncropped frame.
|
||||
crop,
|
||||
/// The region map is drawn, a click on the photograph selects, and the
|
||||
/// column is the mask stack and the selected layer's adjustments.
|
||||
local,
|
||||
/// TRACES: FR-DEV-8
|
||||
/// The repairs are drawn on the photograph, a click places one, and the
|
||||
/// column describes whichever is selected.
|
||||
///
|
||||
/// A mode rather than a panel button for the reason the enum exists at
|
||||
/// all: arming a click on the canvas is something only one tool may be
|
||||
/// doing at a time, and two flags could both be true.
|
||||
spots,
|
||||
}
|
||||
|
||||
/// The develop session, as every panel in the column sees it.
|
||||
///
|
||||
/// Two facts, and the three readings of the second one. They are here rather
|
||||
/// than in any one family's global because all of them need at least one:
|
||||
/// every panel greys out on `enabled`, and which panels are drawn at all is
|
||||
/// the mode's answer.
|
||||
export global Develop {
|
||||
/// Whether there is an open photograph whose edit can be changed.
|
||||
///
|
||||
/// Was `adjust-enabled` on the window root. Every panel in the column
|
||||
/// takes it, which is why it is not in any of their globals.
|
||||
in property <bool> enabled: false;
|
||||
|
||||
/// TRACES: FR-UI-5
|
||||
/// What the develop view is currently doing (see `ViewMode`).
|
||||
///
|
||||
/// One value rather than a flag per mode, so two modes cannot be on at
|
||||
/// once — which, with `crop-mode` a bare bool beside a masking panel that
|
||||
/// armed the canvas through two toggles of its own, they could be. Rust
|
||||
/// owns it: entering a mode has side effects on the session (crop drops
|
||||
/// the zoom, local clears nothing and leaving it clears the selection),
|
||||
/// and a property the interface could set directly would let the view
|
||||
/// change without them — which is why nothing here assigns it and the
|
||||
/// rail's pick goes through `mode-picked` on the window instead.
|
||||
///
|
||||
/// In `crop` the canvas shows the *whole* frame — otherwise the area being
|
||||
/// cropped away would not be on screen to drag across — and the surround
|
||||
/// is greyed.
|
||||
///
|
||||
/// `in-out` because Rust reads it back as well as setting it, to know
|
||||
/// which gesture the canvas is armed for.
|
||||
in-out property <ViewMode> view-mode: ViewMode.photo;
|
||||
|
||||
/// The three readings of the mode, derived once here rather than written
|
||||
/// out at each of the dozen places in `app.slint` that test one.
|
||||
///
|
||||
/// `out`, so nothing outside can set one of them and leave it disagreeing
|
||||
/// with the mode it is supposed to be a reading of.
|
||||
out property <bool> cropping: view-mode == ViewMode.crop;
|
||||
out property <bool> local-mode: view-mode == ViewMode.local;
|
||||
/// TRACES: FR-DEV-8
|
||||
out property <bool> repairing: view-mode == ViewMode.spots;
|
||||
}
|
||||
Reference in New Issue
Block a user