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:
+98
-538
@@ -1,9 +1,10 @@
|
||||
import { Theme } from "theme.slint";
|
||||
import { AdjustPanel, ComposePanel, GroupStrip, ParamRow, TransferPanel, ViewMode } from "adjust.slint";
|
||||
import { CategoryRow, GradientHandle, GradientHandles, HandleRole, MaskPanel, MaskRow, PartRow, SubjectRow } from "masks.slint";
|
||||
import { SpotHandle, SpotHandles, SpotPanel, SpotRole } from "spots.slint";
|
||||
import { Develop, ViewMode } from "session.slint";
|
||||
import { AdjustPanel, Adjustments, ComposePanel, Framing, GroupStrip, ParamRow, Transfer, TransferPanel } 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";
|
||||
import { HistoryPanel, HistoryRow } from "history.slint";
|
||||
import { HistoryPanel, HistoryRow, Steps } from "history.slint";
|
||||
import { LaunchScreen } from "launch.slint";
|
||||
import { IdentityScreen, IdentityPerson, IdentityFace } from "identity.slint";
|
||||
import { LibraryGrid, LibraryCell, TimelineBar, PhotoRoll, KeywordRow, PersonChip } from "library.slint";
|
||||
@@ -11,19 +12,25 @@ import { GestureRow } from "gestures.slint";
|
||||
import { Button, PanelHeading, Label, Value, Caption, Panel, EmptyState, ProgressBar, ActivityRow } from "widgets.slint";
|
||||
import { CollectionsPanel, CollectionRow, OfflinePrompt, CollectionMenu,
|
||||
MembershipSheet, MembershipRow } from "collections.slint";
|
||||
import { HistogramPanel, HistogramView } from "histogram.slint";
|
||||
import { HistogramPanel, HistogramView, Levels } from "histogram.slint";
|
||||
import { RecoveryPrompt } from "recovery.slint";
|
||||
import { PresetSheet, ScopeChips, ScopeKind } from "presets.slint";
|
||||
import { FocusMarks, FocusPanel } from "peaking.slint";
|
||||
import { FocusMarks, FocusPanel, Peaking } from "peaking.slint";
|
||||
import { SettingsPage } from "settings.slint";
|
||||
import { ImportPage } from "import.slint";
|
||||
import { StatusBar, InfoPanel } from "develop.slint";
|
||||
import { Capture, StatusBar, InfoPanel } from "develop.slint";
|
||||
import { ToolRail } from "toolrail.slint";
|
||||
|
||||
export { LibraryCell, TimelineBar, CollectionRow, ActivityRow, HistogramView, PersonChip }
|
||||
export { GestureRow }
|
||||
export { ViewMode, GradientHandle, HandleRole, SpotHandle, SpotRole }
|
||||
|
||||
// The develop view's globals, re-exported so Rust can reach them: a global is
|
||||
// hooked through `window.global::<Adjustments>()` and only what this document
|
||||
// exports appears in the generated API. `session.slint` says why the develop
|
||||
// panels take their wiring this way and why there is one global per family.
|
||||
export { Develop, Capture, Levels, Peaking, Adjustments, Framing, Transfer, Masking, Repair, Steps }
|
||||
|
||||
export component AppWindow inherits Window {
|
||||
title: "DarkRoom";
|
||||
// The one raster asset in the UI, and the exception that the header of
|
||||
@@ -65,49 +72,17 @@ export component AppWindow inherits Window {
|
||||
|
||||
// Current image, for the status strip and empty state.
|
||||
in property <string> filename: "";
|
||||
in property <string> camera: "";
|
||||
/// TRACES: FR-DEV-3
|
||||
/// The lens the file names, and whether a correction profile was found for
|
||||
/// it. Composed in Rust because the sentence depends on a database lookup
|
||||
/// this file cannot see, and because "not recorded" and "no profile" are
|
||||
/// different facts that must not be collapsed into one.
|
||||
in property <string> lens: "";
|
||||
in property <string> exposure: "";
|
||||
in property <string> dimensions: "";
|
||||
in property <int> index: 0;
|
||||
in property <int> total: 0;
|
||||
in property <string> load-error: "";
|
||||
|
||||
/// TRACES: FR-DSP-7
|
||||
/// The counted frame. Set only when the render has settled — a histogram
|
||||
/// of a draft frame is a histogram of an image nobody is reading.
|
||||
in property <HistogramView> histogram;
|
||||
|
||||
/// The same photograph counted in the raw domain — the demosaiced
|
||||
/// scene-linear texture, before white balance, the camera matrix or any
|
||||
/// curve, on an axis of stops below sensor saturation.
|
||||
///
|
||||
/// Beside the display histogram rather than instead of it: the two answer
|
||||
/// different questions and the panel offers both. Unlike the one above it
|
||||
/// this is a property of the *file* and not of the render, so it survives
|
||||
/// a crop, a zoom and every slider — see `raw_histogram.rs`.
|
||||
in property <HistogramView> raw-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`.
|
||||
/// The focus marks themselves, and whether they describe *this* frame.
|
||||
/// Rust's, because they come from a compute pass — see `peaking.slint` for
|
||||
/// why `focus-overlay-ready` is a separate question from
|
||||
/// `Peaking.showing`, and for the three things the photographer chose.
|
||||
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) ---
|
||||
//
|
||||
@@ -125,28 +100,6 @@ export component AppWindow inherits Window {
|
||||
/// resolution against the viewport's, which Slint does not know.
|
||||
in property <bool> magnified: 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.
|
||||
///
|
||||
/// 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 property <ViewMode> view-mode: ViewMode.photo;
|
||||
/// Shorthand for the two conditions half this file tests, so a mode
|
||||
/// comparison is written once rather than at each of a dozen call sites.
|
||||
property <bool> cropping: root.view-mode == ViewMode.crop;
|
||||
property <bool> local-mode: root.view-mode == ViewMode.local;
|
||||
/// TRACES: FR-DEV-8
|
||||
property <bool> repairing: root.view-mode == ViewMode.spots;
|
||||
|
||||
/// The crop rect in fractions of the frame, mirrored from Rust so the
|
||||
/// overlay draws exactly what the pipeline holds.
|
||||
in-out property <float> crop-x: 0.0;
|
||||
@@ -154,20 +107,6 @@ export component AppWindow inherits Window {
|
||||
in-out property <float> crop-w: 1.0;
|
||||
in-out property <float> crop-h: 1.0;
|
||||
|
||||
/// TRACES: FR-DEV-3
|
||||
/// The ratios the crop may be locked to, and which one is chosen.
|
||||
///
|
||||
/// Named by Rust rather than listed here: the set is `CropAspect::CHOICES`
|
||||
/// and the labels come off it, so a ratio added there appears without this
|
||||
/// file changing.
|
||||
in property <[string]> crop-aspects;
|
||||
in property <int> crop-aspect: 0;
|
||||
/// Whether the chosen ratio is standing on its short edge.
|
||||
in property <bool> crop-portrait: false;
|
||||
/// Whether the chosen ratio has a portrait form at all — `Free` and the
|
||||
/// square do not, and the switch says so rather than vanishing.
|
||||
in property <bool> crop-aspect-turnable: false;
|
||||
|
||||
/// Enter a mode, or `photo` to leave whichever one is current.
|
||||
callback mode-picked(ViewMode);
|
||||
/// A dragged crop rect in fractions of the frame, then the corner the drag
|
||||
@@ -175,50 +114,6 @@ export component AppWindow inherits Window {
|
||||
/// shape it has. See `CropOverlay` in crop.slint for why the corner has to
|
||||
/// travel with the rect.
|
||||
callback crop-changed(float, float, float, float, float, float);
|
||||
/// Lock the crop to one of `crop-aspects`, by index.
|
||||
callback crop-aspect-picked(int);
|
||||
/// Stand the chosen ratio on its other edge.
|
||||
callback crop-portrait-toggled();
|
||||
|
||||
// --- rotation, flips and straightening (FR-DEV-3) ---
|
||||
//
|
||||
// Mirrored from the session rather than held here, for the same reason the
|
||||
// crop rect is: Rust clamps and wraps these, so the panel must show what
|
||||
// was actually applied and not what the click asked for.
|
||||
in property <float> straighten: 0.0;
|
||||
/// The straighten slider's travel either way, from the descriptor.
|
||||
in property <float> max-straighten: 45.0;
|
||||
in property <bool> flip-h: false;
|
||||
in property <bool> flip-v: false;
|
||||
/// Any framing edit is in effect — what lights the section's dot and
|
||||
/// enables its reset. Distinct from the crop rect being non-full: a
|
||||
/// rotation or a flip is an edit with the crop still full.
|
||||
in property <bool> framing-modified: false;
|
||||
|
||||
/// Quarter turns, positive clockwise.
|
||||
callback rotate-quarters(int);
|
||||
callback flip-h-toggled();
|
||||
callback flip-v-toggled();
|
||||
callback straighten-changed(float);
|
||||
/// TRACES: FR-DEV-3
|
||||
/// The straightening gesture is over and this is the angle to keep.
|
||||
///
|
||||
/// Reported separately from the value because the auto-crop that follows a
|
||||
/// straighten has to happen once, at the end — see
|
||||
/// `DevelopSession::auto_crop_to_angle`.
|
||||
callback straighten-committed(float);
|
||||
/// Crop, angle, rotation and flips back to neutral, leaving colour alone.
|
||||
callback framing-reset();
|
||||
|
||||
// --- undo and redo (FR-DEV-5) ---
|
||||
//
|
||||
// Rust owns whether there is anywhere to step, because "anywhere" is a
|
||||
// position in a stack of snapshots this side never sees. A whole drag is
|
||||
// one step; the coalescing that makes it so lives in `dr-pipeline`.
|
||||
in property <bool> can-undo: false;
|
||||
in property <bool> can-redo: false;
|
||||
callback undo();
|
||||
callback redo();
|
||||
|
||||
// --- before and after (FR-DEV-7) ---
|
||||
|
||||
@@ -241,20 +136,17 @@ export component AppWindow inherits Window {
|
||||
// --- sampling a neutral off the photograph (FR-DEV-3) ---
|
||||
|
||||
/// TRACES: FR-DEV-3
|
||||
/// Which operation's on-canvas sampler is armed, or -1 for none.
|
||||
///
|
||||
/// Held here rather than in Rust, unlike the view mode beside it, and the
|
||||
/// difference is real: entering a mode has side effects on the session and
|
||||
/// this has none. Arming changes what the next click on the photograph
|
||||
/// means and nothing else — no parameter moves, no history step is taken,
|
||||
/// and the session has nothing to hear about until a point is picked. It
|
||||
/// is one-shot: the click that samples disarms it.
|
||||
///
|
||||
/// An index rather than a bool because arming belongs to a *group*. Two
|
||||
/// operations could offer a sampler and only one of them can be waiting.
|
||||
in-out property <int> sampling-op: -1;
|
||||
/// Shorthand for the condition the canvas tests, written once.
|
||||
property <bool> sampling: root.sampling-op >= 0;
|
||||
///
|
||||
/// Which operation is armed lives in `Adjustments`, with the panel whose
|
||||
/// headings arm it. It is held in the interface rather than in Rust,
|
||||
/// unlike the view mode beside it, and the difference is real: entering a
|
||||
/// mode has side effects on the session and this has none. Arming changes
|
||||
/// what the next click on the photograph means and nothing else — no
|
||||
/// parameter moves, no history step is taken, and the session has nothing
|
||||
/// to hear about until a point is picked. It is one-shot: the click that
|
||||
/// samples disarms it.
|
||||
property <bool> sampling: Adjustments.sampling-op >= 0;
|
||||
/// A neutral was picked, in fractions of the visible image.
|
||||
///
|
||||
/// The operation is not passed: which one a sampled colour belongs to is
|
||||
@@ -262,14 +154,6 @@ export component AppWindow inherits Window {
|
||||
/// knowing. See `dr_pipeline::neutral`.
|
||||
callback neutral-picked(float, float);
|
||||
|
||||
/// Every step, newest first. Rust owns the order and stamps each row with
|
||||
/// its own position in the stack, so nothing here does arithmetic to turn
|
||||
/// a row back into a step.
|
||||
in property <[HistoryRow]> history-rows;
|
||||
/// What undo would take back, resolved. Empty when there is nowhere to go.
|
||||
in property <string> undo-label: "";
|
||||
/// A row's own `index`.
|
||||
callback history-picked(int);
|
||||
/// Scroll-to-zoom: factor, and the anchor in fractions of the visible area.
|
||||
callback zoom-at(float, float, float);
|
||||
callback pan-by(float, float);
|
||||
@@ -826,62 +710,12 @@ export component AppWindow inherits Window {
|
||||
callback next-image();
|
||||
callback prev-image();
|
||||
|
||||
// Adjustment controls, generated from what the pipeline reports it can
|
||||
// do. This window knows the *shape* of a control, never which operations
|
||||
// exist (FR-DEV-3a).
|
||||
in property <[ParamRow]> adjust-rows;
|
||||
// TRACES: FR-DEV-3f
|
||||
// The installed film stocks, "None" first, and which one this photograph
|
||||
// is on. Resolved names: the core publishes ids, and a stock's name is a
|
||||
// product name that does not translate.
|
||||
in property <[string]> film-stocks;
|
||||
in property <int> film-selected: 0;
|
||||
in property <bool> film-can-print: false;
|
||||
in property <bool> film-print: false;
|
||||
callback film-picked(int);
|
||||
callback film-print-toggled(bool);
|
||||
/// TRACES: FR-UI-1 | FR-UI-7
|
||||
/// Whether the adjustment groups are chosen from the tool rail or from the
|
||||
/// strip above the develop column.
|
||||
///
|
||||
/// Owned by Rust, which composes it from the input modality and the
|
||||
/// photographer's override — see `ToolRail::groups-in-rail` for why the
|
||||
/// axis is input rather than platform or width.
|
||||
///
|
||||
/// The two controls are mutually exclusive by construction: this shows one
|
||||
/// and hides the other, so there is never a moment with two ways to
|
||||
/// answer the same question, and no state to keep in step between them.
|
||||
in property <bool> groups-in-rail: false;
|
||||
in property <[string]> adjust-tabs;
|
||||
in property <int> adjust-active-tab: -1;
|
||||
callback adjust-tab-picked(int);
|
||||
in property <bool> adjust-enabled: false;
|
||||
// The tone curve's sampled shape, evaluated by the core so the drawn
|
||||
// line and the applied one cannot disagree.
|
||||
in property <[float]> curve-samples;
|
||||
// The curves that widget can plot, named by the core, and which of them
|
||||
// `curve-samples` describes. Fewer than two means nothing to choose.
|
||||
in property <[string]> curve-channels;
|
||||
in property <int> curve-channel;
|
||||
callback param-changed(int, int, float);
|
||||
callback param-reset(int, int);
|
||||
callback curve-reset(int);
|
||||
callback curve-channel-picked(int);
|
||||
callback reset-all();
|
||||
|
||||
// --- copying settings between photographs (FR-DEV-6) ---
|
||||
//
|
||||
// The clipboard is a window-lifetime thing rather than a view's, which is
|
||||
// why it lives here and not inside the develop column: a copy is taken in
|
||||
// develop and may be pasted onto a selection back in the library grid.
|
||||
/// Whether anything has been copied this session.
|
||||
in property <bool> settings-armed: false;
|
||||
/// What a paste would apply, at the current scope — "3 adjustments".
|
||||
in property <string> settings-summary;
|
||||
/// Whether the copy holds framing that the current setting is dropping.
|
||||
in property <bool> settings-framing-withheld: false;
|
||||
callback copy-settings();
|
||||
callback paste-settings();
|
||||
// why the grid's half of it lives here and not inside the develop column:
|
||||
// a copy is taken in develop and may be pasted onto a selection back in
|
||||
// the library grid. The develop half is `Transfer`, in `adjust.slint`.
|
||||
/// Apply the clipboard to every selected image in the grid.
|
||||
callback paste-settings-to-selection();
|
||||
|
||||
@@ -909,10 +743,6 @@ export component AppWindow inherits Window {
|
||||
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();
|
||||
|
||||
/// TRACES: FR-DEV-6
|
||||
/// Which kinds of edit a copy, paste or preset carries.
|
||||
@@ -1137,16 +967,6 @@ export component AppWindow inherits Window {
|
||||
/// opaque map hides the thing being judged.
|
||||
in property <float> overlay-strength: 0.55;
|
||||
in property <bool> overlay-on: false;
|
||||
/// TRACES: FR-DEV-3
|
||||
/// The photographer's switch for the same overlay, kept separate from
|
||||
/// `overlay-on` because the two answer different questions: `overlay-on`
|
||||
/// is "is there a mask to draw", which Rust decides, and this is "do I
|
||||
/// want to look at it right now", which only they can.
|
||||
///
|
||||
/// Folding them into one property would mean the next recompute — any
|
||||
/// mask edit — silently switched the overlay back on under someone who had
|
||||
/// just turned it off to check their work against the photograph.
|
||||
in-out property <bool> overlay-hidden: false;
|
||||
/// Which part of the source-space overlay the view is showing, in overlay
|
||||
/// pixels. Without it the overlay stays frame-sized while the photograph
|
||||
/// moves under it.
|
||||
@@ -1164,24 +984,14 @@ export component AppWindow inherits Window {
|
||||
/// entered and doing nothing. Arming a click is part of what local mode
|
||||
/// *is*, so it follows the mode and the existence of something to pick.
|
||||
/// TRACES: FR-DEV-19b
|
||||
/// What a drag on the photograph does while a mask is selected: 0 selects
|
||||
/// a subject, 1 paints into the mask, 2 erases from it.
|
||||
in-out property <int> mask-tool: 0;
|
||||
/// TRACES: FR-DEV-19a
|
||||
/// The parts of the selected mask, for the panel.
|
||||
in property <[PartRow]> mask-parts;
|
||||
in property <float> brush-radius: 0.05;
|
||||
in property <float> brush-hardness: 0.5;
|
||||
in property <float> brush-flow: 1.0;
|
||||
|
||||
callback mask-tool-picked(int);
|
||||
callback brush-changed(float, float, float);
|
||||
callback mask-part-selected(string, int);
|
||||
callback mask-part-join-picked(string, int, int);
|
||||
callback mask-part-removed(string, int);
|
||||
callback mask-part-added(string, int);
|
||||
/// TRACES: FR-DEV-19b
|
||||
/// A stroke, in fractions of the photograph as it is currently shown.
|
||||
///
|
||||
/// These stay on the window rather than moving into `Masking` with the
|
||||
/// rest of the mask controls: a stroke is a gesture on the *canvas*, and
|
||||
/// the canvas is this file's. What went into the global is the panel's
|
||||
/// state — which tool is armed, how big the brush is, what parts a mask
|
||||
/// has — because that is what a second copy of the column needs its own
|
||||
/// binding to.
|
||||
callback paint-began(float, float);
|
||||
callback paint-moved(float, float);
|
||||
callback paint-ended();
|
||||
@@ -1190,8 +1000,8 @@ export component AppWindow inherits Window {
|
||||
// so exactly one of them is armed at a time. Without this the first dab of
|
||||
// every stroke would also re-select whatever was under it, and the mask
|
||||
// being painted would be replaced by the one the click made.
|
||||
property <bool> region-picking: root.local-mode && root.segmented && root.mask-tool == 0;
|
||||
property <bool> painting: root.local-mode && root.mask-tool > 0;
|
||||
property <bool> region-picking: Develop.local-mode && Masking.segmented && Masking.tool == 0;
|
||||
property <bool> painting: Develop.local-mode && Masking.tool > 0;
|
||||
|
||||
/// Whether shift is down, tracked by the develop key scope below.
|
||||
///
|
||||
@@ -1200,16 +1010,6 @@ export component AppWindow inherits Window {
|
||||
/// nothing outside it has any business setting it.
|
||||
property <bool> shift-held: false;
|
||||
|
||||
in property <[MaskRow]> mask-rows;
|
||||
in property <[SubjectRow]> subject-rows;
|
||||
in property <[CategoryRow]> category-rows;
|
||||
in property <bool> segmented: false;
|
||||
in property <bool> segmenting: false;
|
||||
in property <bool> refining: false;
|
||||
/// The selected layer's name, already resolved, or "ADJUST" when the
|
||||
/// controls are global. Names the adjust panel's heading.
|
||||
in property <string> adjust-scope: "ADJUST";
|
||||
|
||||
/// The selected gradient's handles, in fractions of the shown image.
|
||||
/// Empty unless a gradient layer is selected in local mode.
|
||||
in property <[GradientHandle]> gradient-handles;
|
||||
@@ -1247,50 +1047,9 @@ export component AppWindow inherits Window {
|
||||
callback spot-handle-released();
|
||||
/// A repair chosen, so the column describes it.
|
||||
callback spot-selected(string);
|
||||
/// Take the selected repair off the photograph.
|
||||
callback spot-removed(string);
|
||||
/// Which repair the column is describing, or "" for none.
|
||||
in-out property <string> selected-spot: "";
|
||||
/// The selected repair's settings, and how many repairs there are.
|
||||
///
|
||||
/// Pushed as scalars rather than read off `spot-handles`, because the
|
||||
/// circles carry what is *drawn* — a radius already mapped through the
|
||||
/// framing into fractions of the shown image — and the panel edits what is
|
||||
/// *stored*. Deriving one from the other would mean a slider that moved
|
||||
/// differently at different zoom levels.
|
||||
in property <int> spot-count: 0;
|
||||
in property <float> spot-radius: 0.012;
|
||||
in property <float> spot-feather: 0.35;
|
||||
in property <float> spot-opacity: 1.0;
|
||||
/// 0 heal, 1 clone.
|
||||
in property <int> spot-mode: 0;
|
||||
|
||||
callback spot-radius-changed(float);
|
||||
callback spot-feather-changed(float);
|
||||
callback spot-opacity-changed(float);
|
||||
callback spot-mode-picked(int);
|
||||
|
||||
callback segment-image(bool);
|
||||
/// A click on the photograph, in fractions of the shown image, plus
|
||||
/// whether it should extend the selection rather than replace it.
|
||||
callback region-picked(float, float, bool);
|
||||
callback mask-selected(string, bool);
|
||||
callback mask-removed(string);
|
||||
callback mask-refined(string);
|
||||
callback mask-toggled(string, bool);
|
||||
callback mask-invert-toggled(string, bool);
|
||||
callback mask-opacity-changed(string, float);
|
||||
callback mask-feather-changed(string, float);
|
||||
callback mask-refine-changed(string, float);
|
||||
callback mask-falloff-picked(string, int);
|
||||
callback mask-morphology-picked(string, int);
|
||||
callback mask-morph-radius-changed(string, float);
|
||||
callback mask-band-changed(string, float, float, float);
|
||||
callback mask-hue-changed(string, float, float);
|
||||
callback add-gradient-mask(bool);
|
||||
callback add-range-mask(bool);
|
||||
callback add-subject-mask(int);
|
||||
callback add-category-mask(string);
|
||||
|
||||
/// Whether the develop column — image info, geometry, adjust — is shown.
|
||||
///
|
||||
@@ -1815,7 +1574,7 @@ in property <bool> panel-visible: true;
|
||||
offset: root.library-offset;
|
||||
selected-count: root.library-selected-count;
|
||||
scope-label: root.collection-scope-label;
|
||||
settings-armed: root.settings-armed;
|
||||
settings-armed: Transfer.armed;
|
||||
paste-settings-to-selection => {
|
||||
root.paste-settings-to-selection();
|
||||
}
|
||||
@@ -1966,15 +1725,15 @@ in property <bool> panel-visible: true;
|
||||
export-label: root.export-label;
|
||||
export-busy: root.export-busy;
|
||||
export-status: root.export-status;
|
||||
can-undo: root.can-undo;
|
||||
can-redo: root.can-redo;
|
||||
can-undo: Steps.can-undo;
|
||||
can-redo: Steps.can-redo;
|
||||
back-to-library() => { root.back-to-library(); }
|
||||
open-people() => { root.identity-open(); }
|
||||
open-settings() => { root.settings-open(); }
|
||||
toggle-panel() => { root.toggle-panel(); }
|
||||
export-image() => { root.export-image(); }
|
||||
undo() => { root.undo(); }
|
||||
redo() => { root.redo(); }
|
||||
undo() => { Steps.undo(); }
|
||||
redo() => { Steps.redo(); }
|
||||
}
|
||||
|
||||
// The develop view's frame: the rail, the photograph, the column.
|
||||
@@ -2050,7 +1809,7 @@ in property <bool> panel-visible: true;
|
||||
y: 0;
|
||||
height: parent.height;
|
||||
enabled: root.total > 0 && root.load-error == "";
|
||||
mode: root.view-mode;
|
||||
mode: Develop.view-mode;
|
||||
picked(m) => { root.mode-picked(m); }
|
||||
|
||||
// The same model and the same callback the strip below
|
||||
@@ -2059,10 +1818,10 @@ in property <bool> panel-visible: true;
|
||||
// told which control was pressed and has no reason to
|
||||
// care — the choice between them is a presentation
|
||||
// decision, and it stays one.
|
||||
groups-in-rail: root.groups-in-rail;
|
||||
tabs: root.adjust-tabs;
|
||||
active-tab: root.adjust-active-tab;
|
||||
group-picked(i) => { root.adjust-tab-picked(i); }
|
||||
groups-in-rail: Adjustments.groups-in-rail;
|
||||
tabs: Adjustments.tabs;
|
||||
active-tab: Adjustments.active-tab;
|
||||
group-picked(i) => { Adjustments.tab-picked(i); }
|
||||
}
|
||||
|
||||
// The canvas: compute output composited directly. No CPU
|
||||
@@ -2111,7 +1870,7 @@ in property <bool> panel-visible: true;
|
||||
// it is a diagnostic and not an edit: it must not reach
|
||||
// the histogram, an export, or the texture the develop
|
||||
// pass hands the compositor.
|
||||
if root.overlay-on && !root.overlay-hidden && root.total > 0: Image {
|
||||
if root.overlay-on && !Masking.overlay-hidden && root.total > 0: Image {
|
||||
x: parent.shown-x;
|
||||
y: parent.shown-y;
|
||||
width: parent.shown-w;
|
||||
@@ -2208,7 +1967,7 @@ in property <bool> panel-visible: true;
|
||||
x: 0; y: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
enabled: !root.cropping;
|
||||
enabled: !Develop.cropping;
|
||||
|
||||
property <float> last-scale: 1.0;
|
||||
|
||||
@@ -2239,7 +1998,7 @@ in property <bool> panel-visible: true;
|
||||
width: parent.shown-w;
|
||||
height: parent.shown-h;
|
||||
mouse-cursor: MouseCursor.crosshair;
|
||||
enabled: !root.cropping;
|
||||
enabled: !Develop.cropping;
|
||||
|
||||
clicked => {
|
||||
root.region-picked(
|
||||
@@ -2276,7 +2035,7 @@ in property <bool> panel-visible: true;
|
||||
width: parent.shown-w;
|
||||
height: parent.shown-h;
|
||||
mouse-cursor: crosshair;
|
||||
enabled: !root.cropping;
|
||||
enabled: !Develop.cropping;
|
||||
|
||||
pointer-event(ev) => {
|
||||
if ev.kind == PointerEventKind.down {
|
||||
@@ -2313,13 +2072,13 @@ in property <bool> panel-visible: true;
|
||||
// Below the circles declared further down, so a press that
|
||||
// lands on an existing repair takes hold of it instead of
|
||||
// making another one on top.
|
||||
if root.repairing && root.total > 0 && root.load-error == "": TouchArea {
|
||||
if Develop.repairing && root.total > 0 && root.load-error == "": TouchArea {
|
||||
x: parent.shown-x;
|
||||
y: parent.shown-y;
|
||||
width: parent.shown-w;
|
||||
height: parent.shown-h;
|
||||
mouse-cursor: MouseCursor.crosshair;
|
||||
enabled: !root.cropping;
|
||||
enabled: !Develop.cropping;
|
||||
|
||||
clicked => {
|
||||
root.spot-placed(
|
||||
@@ -2350,7 +2109,7 @@ in property <bool> panel-visible: true;
|
||||
width: parent.shown-w;
|
||||
height: parent.shown-h;
|
||||
mouse-cursor: MouseCursor.crosshair;
|
||||
enabled: !root.cropping;
|
||||
enabled: !Develop.cropping;
|
||||
|
||||
clicked => {
|
||||
root.neutral-picked(
|
||||
@@ -2362,7 +2121,7 @@ in property <bool> panel-visible: true;
|
||||
// pan — a second sample, and the photographer
|
||||
// would have to remember to put a tool away that
|
||||
// has already done its job.
|
||||
root.sampling-op = -1;
|
||||
Adjustments.sampling-op = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2373,7 +2132,7 @@ in property <bool> panel-visible: true;
|
||||
// A pan is only meaningful once there is something outside
|
||||
// the viewport to reach.
|
||||
mouse-cursor: root.zoomed ? MouseCursor.grab : MouseCursor.default;
|
||||
enabled: !root.cropping;
|
||||
enabled: !Develop.cropping;
|
||||
|
||||
property <length> last-x;
|
||||
property <length> last-y;
|
||||
@@ -2450,7 +2209,7 @@ in property <bool> panel-visible: true;
|
||||
//
|
||||
// Placed over the fitted image, so the fractions it draws are
|
||||
// fractions of the picture. See `CropOverlay` in crop.slint.
|
||||
if root.cropping && root.total > 0 && root.load-error == "": CropOverlay {
|
||||
if Develop.cropping && root.total > 0 && root.load-error == "": CropOverlay {
|
||||
x: canvas-area.shown-x;
|
||||
y: canvas-area.shown-y;
|
||||
width: canvas-area.shown-w;
|
||||
@@ -2580,9 +2339,9 @@ in property <bool> panel-visible: true;
|
||||
if (event.modifiers.control
|
||||
&& (event.text == "z" || event.text == "Z")) {
|
||||
if (event.modifiers.shift) {
|
||||
root.redo();
|
||||
Steps.redo();
|
||||
} else {
|
||||
root.undo();
|
||||
Steps.undo();
|
||||
}
|
||||
return accept;
|
||||
}
|
||||
@@ -2592,10 +2351,10 @@ in property <bool> panel-visible: true;
|
||||
// photographs, and a key that means two things
|
||||
// depending on a mode the user has forgotten they
|
||||
// are in is how work disappears.
|
||||
if (root.repairing && root.selected-spot != ""
|
||||
if (Develop.repairing && Repair.selected != ""
|
||||
&& (event.text == Key.Delete
|
||||
|| event.text == Key.Backspace)) {
|
||||
root.spot-removed(root.selected-spot);
|
||||
Repair.removed(Repair.selected);
|
||||
return accept;
|
||||
}
|
||||
// GESTURE: Copy the settings from this photograph
|
||||
@@ -2630,12 +2389,12 @@ in property <bool> panel-visible: true;
|
||||
// clear, it is a keystroke that should do nothing.
|
||||
if (event.modifiers.control
|
||||
&& (event.text == "c" || event.text == "C")) {
|
||||
root.copy-settings();
|
||||
Transfer.copy();
|
||||
return accept;
|
||||
}
|
||||
if (event.modifiers.control && root.settings-armed
|
||||
if (event.modifiers.control && Transfer.armed
|
||||
&& (event.text == "v" || event.text == "V")) {
|
||||
root.paste-settings();
|
||||
Transfer.paste();
|
||||
return accept;
|
||||
}
|
||||
// GESTURE: Change which group of adjustments is on screen
|
||||
@@ -2659,18 +2418,18 @@ in property <bool> panel-visible: true;
|
||||
// the groups arrives back at the whole set instead
|
||||
// of being trapped in the last one.
|
||||
if (event.text == "]") {
|
||||
root.adjust-tab-picked(
|
||||
(root.adjust-active-tab + 1
|
||||
>= root.adjust-tabs.length)
|
||||
Adjustments.tab-picked(
|
||||
(Adjustments.active-tab + 1
|
||||
>= Adjustments.tabs.length)
|
||||
? -1
|
||||
: (root.adjust-active-tab + 1));
|
||||
: (Adjustments.active-tab + 1));
|
||||
return accept;
|
||||
}
|
||||
if (event.text == "[") {
|
||||
root.adjust-tab-picked(
|
||||
(root.adjust-active-tab - 1 < -1)
|
||||
? (root.adjust-tabs.length - 1)
|
||||
: (root.adjust-active-tab - 1));
|
||||
Adjustments.tab-picked(
|
||||
(Adjustments.active-tab - 1 < -1)
|
||||
? (Adjustments.tabs.length - 1)
|
||||
: (Adjustments.active-tab - 1));
|
||||
return accept;
|
||||
}
|
||||
// GESTURE: Look at the photograph at 1:1
|
||||
@@ -2786,7 +2545,7 @@ in property <bool> panel-visible: true;
|
||||
spacing: 6px;
|
||||
alignment: start;
|
||||
|
||||
if root.view-mode != ViewMode.photo: Button {
|
||||
if Develop.view-mode != ViewMode.photo: Button {
|
||||
// Names the mode being left rather than saying
|
||||
// "Done", which was unambiguous while there was
|
||||
// one mode and would not be with two.
|
||||
@@ -2796,9 +2555,9 @@ in property <bool> panel-visible: true;
|
||||
// exit after one of the mode's controls, when the
|
||||
// rail beside it named the mode, would be the same
|
||||
// control answering to two words.
|
||||
text: root.cropping
|
||||
text: Develop.cropping
|
||||
? "Done Composing"
|
||||
: (root.repairing ? "Done Repairing" : "Done Masking");
|
||||
: (Develop.repairing ? "Done Repairing" : "Done Masking");
|
||||
active: true;
|
||||
clicked => { root.mode-picked(ViewMode.photo); }
|
||||
}
|
||||
@@ -2861,7 +2620,7 @@ in property <bool> panel-visible: true;
|
||||
// same thing on both edges; see the focus scope below.
|
||||
Button {
|
||||
text: "Before";
|
||||
enabled: root.adjust-enabled;
|
||||
enabled: Develop.enabled;
|
||||
active: root.showing-original;
|
||||
accessible-checkable: true;
|
||||
accessible-checked: root.showing-original;
|
||||
@@ -2992,18 +2751,12 @@ in property <bool> panel-visible: true;
|
||||
// would both sit at its origin and overlap. The strip is pinned by
|
||||
// being outside the Flickable rather than by any coordinate.
|
||||
VerticalLayout {
|
||||
GroupStrip {
|
||||
// Stands down when the rail is carrying the
|
||||
// groups. `enabled` rather than an `if`, because
|
||||
// the strip already collapses itself to zero
|
||||
// height on it — and a conditional child in this
|
||||
// layout is the shape that has caused binding
|
||||
// loops in this file before.
|
||||
enabled: root.adjust-enabled && !root.groups-in-rail;
|
||||
tabs: root.adjust-tabs;
|
||||
active-tab: root.adjust-active-tab;
|
||||
picked(i) => { root.adjust-tab-picked(i); }
|
||||
}
|
||||
// Stands down when the rail is carrying the groups, and
|
||||
// collapses itself to zero height rather than being
|
||||
// conditioned here — a conditional child in this layout is
|
||||
// the shape that has caused binding loops in this file
|
||||
// before. `GroupStrip.live` holds the rule.
|
||||
GroupStrip { }
|
||||
|
||||
Flickable {
|
||||
viewport-height: column.preferred-height;
|
||||
@@ -3076,14 +2829,9 @@ in property <bool> panel-visible: true;
|
||||
// screen. `masks.slint` carries the same note for
|
||||
// the same reason.
|
||||
column := VerticalLayout {
|
||||
if !root.local-mode && !root.repairing: InfoPanel {
|
||||
camera: root.camera;
|
||||
lens: root.lens;
|
||||
exposure: root.exposure;
|
||||
dimensions: root.dimensions;
|
||||
}
|
||||
if !Develop.local-mode && !Develop.repairing: InfoPanel { }
|
||||
|
||||
if !root.local-mode && !root.repairing: Rectangle {
|
||||
if !Develop.local-mode && !Develop.repairing: Rectangle {
|
||||
height: 1px;
|
||||
background: Theme.rule;
|
||||
}
|
||||
@@ -3100,10 +2848,7 @@ in property <bool> panel-visible: true;
|
||||
// disagreement is real and is N3's to close; taking
|
||||
// the instrument away instead would be a worse
|
||||
// answer than an honest one that is not yet scoped.
|
||||
HistogramPanel {
|
||||
data: root.histogram;
|
||||
raw-data: root.raw-histogram;
|
||||
}
|
||||
HistogramPanel { }
|
||||
|
||||
Rectangle {
|
||||
height: 1px;
|
||||
@@ -3115,15 +2860,7 @@ in property <bool> panel-visible: true;
|
||||
// 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); }
|
||||
}
|
||||
FocusPanel { }
|
||||
|
||||
Rectangle {
|
||||
height: 1px;
|
||||
@@ -3134,39 +2871,9 @@ in property <bool> panel-visible: true;
|
||||
// made rather than how it is applied: the frame is decided
|
||||
// by eye first and the pipeline runs it last (see
|
||||
// `dr_pipeline::framing` on the coordinate order).
|
||||
if !root.local-mode && !root.repairing: ComposePanel {
|
||||
enabled: root.adjust-enabled;
|
||||
angle: root.straighten;
|
||||
max-straighten: root.max-straighten;
|
||||
flip-h: root.flip-h;
|
||||
flip-v: root.flip-v;
|
||||
modified: root.framing-modified;
|
||||
if !Develop.local-mode && !Develop.repairing: ComposePanel { }
|
||||
|
||||
// The ratio chips belong to the crop tool, so
|
||||
// they appear with it. Shown at all times they
|
||||
// would be a control for a gesture that is not
|
||||
// on screen; hidden behind a lid they would be
|
||||
// a feature nobody finds.
|
||||
cropping: root.cropping;
|
||||
aspects: root.crop-aspects;
|
||||
aspect: root.crop-aspect;
|
||||
portrait: root.crop-portrait;
|
||||
aspect-turnable: root.crop-aspect-turnable;
|
||||
aspect-picked(i) => { root.crop-aspect-picked(i); }
|
||||
portrait-toggled => { root.crop-portrait-toggled(); }
|
||||
|
||||
rotate(turns) => { root.rotate-quarters(turns); }
|
||||
flip-h-toggled => { root.flip-h-toggled(); }
|
||||
flip-v-toggled => { root.flip-v-toggled(); }
|
||||
angle-changed(v) => { root.straighten-changed(v); }
|
||||
angle-committed(v) => {
|
||||
root.straighten-committed(v);
|
||||
}
|
||||
angle-reset => { root.straighten-changed(0); }
|
||||
reset => { root.framing-reset(); }
|
||||
}
|
||||
|
||||
if !root.local-mode && !root.repairing: Rectangle {
|
||||
if !Develop.local-mode && !Develop.repairing: Rectangle {
|
||||
height: 1px;
|
||||
background: Theme.rule;
|
||||
}
|
||||
@@ -3176,23 +2883,7 @@ in property <bool> panel-visible: true;
|
||||
// burying it under thirty sliders would put the one
|
||||
// control that operates on all of them below all of
|
||||
// them.
|
||||
if !root.local-mode && !root.repairing: TransferPanel {
|
||||
enabled: root.adjust-enabled;
|
||||
armed: root.settings-armed;
|
||||
summary: root.settings-summary;
|
||||
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;
|
||||
}
|
||||
}
|
||||
if !Develop.local-mode && !Develop.repairing: TransferPanel { }
|
||||
|
||||
Rectangle {
|
||||
height: 1px;
|
||||
@@ -3213,143 +2904,21 @@ in property <bool> panel-visible: true;
|
||||
// terms as the mask panel: not a panel among peers
|
||||
// that quietly re-points the sliders below it, but
|
||||
// the whole of what this mode has to say.
|
||||
if root.repairing: SpotPanel {
|
||||
enabled: root.adjust-enabled;
|
||||
has-selection: root.selected-spot != "";
|
||||
count: root.spot-count;
|
||||
radius: root.spot-radius;
|
||||
feather: root.spot-feather;
|
||||
spot-opacity: root.spot-opacity;
|
||||
mode: root.spot-mode;
|
||||
if Develop.repairing: SpotPanel { }
|
||||
|
||||
radius-changed(v) => { root.spot-radius-changed(v); }
|
||||
feather-changed(v) => { root.spot-feather-changed(v); }
|
||||
opacity-changed(v) => { root.spot-opacity-changed(v); }
|
||||
mode-picked(i) => { root.spot-mode-picked(i); }
|
||||
removed => { root.spot-removed(root.selected-spot); }
|
||||
}
|
||||
|
||||
if root.repairing: Rectangle {
|
||||
if Develop.repairing: Rectangle {
|
||||
height: 1px;
|
||||
background: Theme.rule;
|
||||
}
|
||||
|
||||
if root.local-mode: MaskPanel {
|
||||
enabled: root.adjust-enabled;
|
||||
masks: root.mask-rows;
|
||||
subjects: root.subject-rows;
|
||||
categories: root.category-rows;
|
||||
segmented: root.segmented;
|
||||
segmenting: root.segmenting;
|
||||
refining: root.refining;
|
||||
// Two-way: the panel is where it is toggled and
|
||||
// the canvas is what obeys it, so neither owns
|
||||
// the value alone.
|
||||
overlay-hidden <=> root.overlay-hidden;
|
||||
if Develop.local-mode: MaskPanel { }
|
||||
|
||||
parts: root.mask-parts;
|
||||
tool: root.mask-tool;
|
||||
brush-radius: root.brush-radius;
|
||||
brush-hardness: root.brush-hardness;
|
||||
brush-flow: root.brush-flow;
|
||||
|
||||
segment(fine) => { root.segment-image(fine); }
|
||||
tool-picked(i) => {
|
||||
root.mask-tool = i;
|
||||
root.mask-tool-picked(i);
|
||||
}
|
||||
brush-changed(r, h, f) => { root.brush-changed(r, h, f); }
|
||||
part-selected(id, i) => { root.mask-part-selected(id, i); }
|
||||
part-join-picked(id, i, j) => {
|
||||
root.mask-part-join-picked(id, i, j);
|
||||
}
|
||||
part-removed(id, i) => { root.mask-part-removed(id, i); }
|
||||
part-added(id, j) => { root.mask-part-added(id, j); }
|
||||
mask-selected(id, extend) => { root.mask-selected(id, extend); }
|
||||
mask-removed(id) => { root.mask-removed(id); }
|
||||
mask-refined(id) => { root.mask-refined(id); }
|
||||
mask-toggled(id, on) => { root.mask-toggled(id, on); }
|
||||
mask-invert-toggled(id, on) => {
|
||||
root.mask-invert-toggled(id, on);
|
||||
}
|
||||
mask-opacity-changed(id, v) => {
|
||||
root.mask-opacity-changed(id, v);
|
||||
}
|
||||
mask-refine-changed(id, v) => {
|
||||
root.mask-refine-changed(id, v);
|
||||
}
|
||||
mask-feather-changed(id, v) => {
|
||||
root.mask-feather-changed(id, v);
|
||||
}
|
||||
mask-falloff-picked(id, i) => {
|
||||
root.mask-falloff-picked(id, i);
|
||||
}
|
||||
mask-morphology-picked(id, i) => {
|
||||
root.mask-morphology-picked(id, i);
|
||||
}
|
||||
mask-morph-radius-changed(id, v) => {
|
||||
root.mask-morph-radius-changed(id, v);
|
||||
}
|
||||
mask-band-changed(id, lo, hi, soft) => {
|
||||
root.mask-band-changed(id, lo, hi, soft);
|
||||
}
|
||||
mask-hue-changed(id, h, w) => {
|
||||
root.mask-hue-changed(id, h, w);
|
||||
}
|
||||
add-gradient(radial) => { root.add-gradient-mask(radial); }
|
||||
add-range(chromatic) => { root.add-range-mask(chromatic); }
|
||||
add-subject(i) => { root.add-subject-mask(i); }
|
||||
add-category(n) => { root.add-category-mask(n); }
|
||||
}
|
||||
|
||||
if root.local-mode: Rectangle {
|
||||
if Develop.local-mode: Rectangle {
|
||||
height: 1px;
|
||||
background: Theme.rule;
|
||||
}
|
||||
|
||||
adjust := AdjustPanel {
|
||||
rows: root.adjust-rows;
|
||||
enabled: root.adjust-enabled;
|
||||
scope: root.adjust-scope;
|
||||
curve-samples: root.curve-samples;
|
||||
curve-channels: root.curve-channels;
|
||||
curve-channel: root.curve-channel;
|
||||
curve-channel-picked(i) => {
|
||||
root.curve-channel-picked(i);
|
||||
}
|
||||
param-changed(op, param, value) => {
|
||||
root.param-changed(op, param, value);
|
||||
}
|
||||
param-reset(op, param) => {
|
||||
root.param-reset(op, param);
|
||||
}
|
||||
curve-reset(op) => { root.curve-reset(op); }
|
||||
// A section's reset and a curve's reset are the same
|
||||
// action — every parameter of one operation back to
|
||||
// its default — so they share the one callback rather
|
||||
// than duplicating a handler that would have to be
|
||||
// kept in step with it.
|
||||
op-reset(op) => { root.curve-reset(op); }
|
||||
reset-all => { root.reset-all(); }
|
||||
// TRACES: FR-DEV-3
|
||||
// Arming is a toggle and it is resolved here,
|
||||
// not in Rust: it changes what a click on the
|
||||
// photograph does and nothing about the edit,
|
||||
// so there is nothing for the session to hear
|
||||
// about until a point is actually picked.
|
||||
sampling-op: root.sampling-op;
|
||||
sampler-armed(op) => {
|
||||
root.sampling-op =
|
||||
root.sampling-op == op ? -1 : op;
|
||||
}
|
||||
// TRACES: FR-DEV-3f
|
||||
film-stocks: root.film-stocks;
|
||||
film-selected: root.film-selected;
|
||||
film-can-print: root.film-can-print;
|
||||
film-print: root.film-print;
|
||||
film-picked(i) => { root.film-picked(i); }
|
||||
film-print-toggled(on) => { root.film-print-toggled(on); }
|
||||
}
|
||||
adjust := AdjustPanel { }
|
||||
|
||||
Rectangle {
|
||||
height: 1px;
|
||||
@@ -3369,16 +2938,7 @@ in property <bool> panel-visible: true;
|
||||
// and a list that emptied when the photographer
|
||||
// entered the mode that produces the most steps
|
||||
// would be a list they stopped trusting.
|
||||
HistoryPanel {
|
||||
rows: root.history-rows;
|
||||
enabled: root.adjust-enabled;
|
||||
can-undo: root.can-undo;
|
||||
can-redo: root.can-redo;
|
||||
undo-label: root.undo-label;
|
||||
undo => { root.undo(); }
|
||||
redo => { root.redo(); }
|
||||
picked(i) => { root.history-picked(i); }
|
||||
}
|
||||
HistoryPanel { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user