Review everything shipped this weekend, and fix what the reviewers caught

Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
Gabriel Brown
2026-08-24 13:29:42 -04:00
parent ffce48964e
commit 07db1068f1
42 changed files with 959 additions and 219 deletions
@@ -1,5 +1,5 @@
// A slider whose track carries a meaning, and whose value is committed once the
// drag settles rather than on every pixel.
// gesture is over rather than on every pixel.
//
// Two rows on the Displays page need something SliderRow cannot give them:
//
@@ -8,7 +8,14 @@
// like, and this is the one slider whose numbers most people cannot picture.
// * The SDR trims, which write through the display transaction. A transaction
// per pixel of drag would arm a fifteen-second countdown dozens of times;
// the value is applied once, when the pointer stops moving.
// the value is applied once, when the button comes up.
//
// On release, not on an idle timer. Holding a slider still for a third of a
// second is not the end of a gesture, and the commit an idle timer made
// mid-hold armed a display transaction that turned this row's `enabled` false
// with the button still down -- the control went dead under the hand using it.
// The wheel has no release, so it keeps the timer, and that is all the timer is
// for now.
//
// Not schema-bound and not a SettingRow: the caller says what the value is and
// what to do with a new one, and the row stacks its control below the label in
@@ -59,6 +66,16 @@ Item {
return colors[Math.min(index, colors.length - 1)];
}
// Hands the pending value to the caller. Called on release, and by the
// wheel's idle timer, which is the one input that never has one.
function commit(): void {
commitTimer.stop();
if (root.pending === null)
return;
root.committed(root.pending);
releaseTimer.restart();
}
function quantise(ratio: real): real {
const raw = root.minimum + ratio * (root.maximum - root.minimum);
const snapped = Math.round(raw / root.step) * root.step;
@@ -166,7 +183,6 @@ Item {
function move(positionX: real): void {
root.pending = root.quantise(
Math.max(0, Math.min(1, (positionX - 8) / track.width)));
commitTimer.restart();
}
onPressed: event => drag.move(event.x)
@@ -174,6 +190,14 @@ Item {
if (drag.pressed)
drag.move(event.x);
}
onReleased: root.commit()
// A grab taken away mid-drag is not a decision. The row goes
// back to showing whatever is really in effect rather than
// keeping a number nobody asked it to apply.
onCanceled: {
commitTimer.stop();
root.pending = null;
}
onWheel: event => {
const direction = event.angleDelta.y > 0 ? 1 : -1;
root.pending = Math.max(root.minimum,
@@ -208,15 +232,13 @@ Item {
color: Theme.alpha(Theme.fg, 0.065)
}
// The wheel's release. A notch is a whole gesture on its own, and a hand
// spinning through a range means one commit at the end of the spin rather
// than one per notch -- there is no button coming up to say when that is.
Timer {
id: commitTimer
interval: root.commitDelay
onTriggered: {
if (root.pending === null)
return;
root.committed(root.pending);
releaseTimer.restart();
}
onTriggered: root.commit()
}
// Hands the readout back to whatever is really in effect. If the change was