Merge branch 'worktree-agent-a89309a856c8f4947' into integration

This commit is contained in:
2026-08-22 19:00:56 +02:00
11 changed files with 1807 additions and 233 deletions
+59 -13
View File
@@ -365,10 +365,17 @@ component ParamControl inherits Rectangle {
in property <ParamRow> data;
/// Curve rows only; ignored by every other kind.
in property <[float]> curve-samples;
/// The curves this widget can plot, named. Empty, or one entry, where
/// there is nothing to choose between — see `curve-channel-picked`.
in property <[string]> curve-channels;
/// Which of `curve-channels` is on the grid.
in property <int> curve-channel;
callback param-changed(int, int, float);
callback param-reset(int, int);
callback curve-reset(int);
/// Plot a different one of the operation's curves.
callback curve-channel-picked(int);
callback drag-changed(bool);
height: layout.preferred-height;
@@ -420,20 +427,49 @@ component ParamControl inherits Rectangle {
}
}
if root.data.kind == "curve": CurveEditor {
points: root.data.points;
samples: root.curve-samples;
drag-changed(on) => { root.drag-changed(on); }
// A point carries two parameters, so the parameter index is the
// row's base plus the point's offset. This component still knows
// nothing about which operation it belongs to.
point-moved(point, x, y) => {
root.param-changed(
root.data.op-index, root.data.param-index + point * 2, x);
root.param-changed(
root.data.op-index, root.data.param-index + point * 2 + 1, y);
// A curve, and — where the operation offers more than one — the choice
// of which curve is on the grid.
//
// One plot rather than four stacked ones: the curves are read against
// the diagonal and against each other, which needs the grid large, and
// four grids at a quarter of the width would each be too small to
// place a point in. So the selector switches the subject of a single
// plot, and the names in it come from the core — this file does not
// know that a colour channel is what is being chosen between, only
// that the widget said it spans several named things.
if root.data.kind == "curve": VerticalLayout {
spacing: Theme.gap-sm;
if root.curve-channels.length > 1: Segmented {
// The operation's own name, which nothing else in this row
// draws: a curve row heads no group, so without this the plot
// would sit in the panel unlabelled.
label: root.data.op-label;
options: root.curve-channels;
selected: root.curve-channel;
picked(i) => { root.curve-channel-picked(i); }
}
CurveEditor {
points: root.data.points;
samples: root.curve-samples;
drag-changed(on) => { root.drag-changed(on); }
// A point carries two parameters, so the parameter index is
// the row's base plus the point's offset. The base is the
// first point of the curve *on show*, so switching curve
// re-points the drag and this component still knows nothing
// about which operation — or which curve — it is drawing.
point-moved(point, x, y) => {
root.param-changed(
root.data.op-index, root.data.param-index + point * 2, x);
root.param-changed(
root.data.op-index, root.data.param-index + point * 2 + 1, y);
}
// Resetting a curve resets the operation, which is all four of
// them — a photographer who double-clicks to start again means
// the control, not the curve that happens to be on show.
reset => { root.curve-reset(root.data.op-index); }
}
reset => { root.curve-reset(root.data.op-index); }
}
}
}
@@ -825,9 +861,16 @@ export component AdjustPanel inherits Rectangle {
/// The tone curve's sampled shape, evaluated in Rust by the same spline
/// the shader runs so the drawn line cannot disagree with the applied one.
in property <[float]> curve-samples;
/// The curves the tone curve widget can plot, named by the core. Fewer
/// than two of them means there is nothing to choose and no selector.
in property <[string]> curve-channels;
/// Which of them `curve-samples` and the row's points describe.
in property <int> curve-channel;
callback param-changed(int, int, float);
callback param-reset(int, int);
callback curve-reset(int);
/// Plot a different one of the curve's curves.
callback curve-channel-picked(int);
/// Return every parameter of one operation to its default — the reset on
/// a section's own header, beside the panel-wide one.
callback op-reset(int);
@@ -986,12 +1029,15 @@ export component AdjustPanel inherits Rectangle {
ParamControl {
data: row;
curve-samples: root.curve-samples;
curve-channels: root.curve-channels;
curve-channel: root.curve-channel;
drag-changed(on) => { root.slider-dragging = on; }
param-changed(op, param, v) => {
root.param-changed(op, param, v);
}
param-reset(op, param) => { root.param-reset(op, param); }
curve-reset(op) => { root.curve-reset(op); }
curve-channel-picked(i) => { root.curve-channel-picked(i); }
}
}
}
+10
View File
@@ -716,9 +716,14 @@ export component AppWindow inherits Window {
// 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) ---
@@ -2177,6 +2182,11 @@ in property <bool> panel-visible: true;
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);
}