Make every settings row reachable, and every accessibility switch honest

Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
Gabriel Brown
2026-08-24 21:03:36 -04:00
parent e1ff25fc66
commit 9ffaf45a4d
33 changed files with 2384 additions and 76 deletions
@@ -81,6 +81,22 @@ Item {
return root.step < 1 ? Math.round(clamped * 100) / 100 : clamped;
}
// One schema step, from the arrow keys, committed through the same debounce
// the pointer drag uses -- holding an arrow reads as a drag rather than as
// a burst of writes the compositor would spend the whole time rejecting.
function nudge(steps: int): void {
const raw = root.shown + steps * root.step;
const clamped = Math.max(root.minimum, Math.min(root.maximum, raw));
root.pending = root.step < 1 ? Math.round(clamped * 100) / 100 : clamped;
commitTimer.restart();
}
// What a screen reader is told the slider is sitting on. Qt 6.11's attached
// Accessible type carries no structured value or range, so the reading and
// its bounds go in the description, in the row's own display units.
readonly property string reading:
`${root.display(root.shown)}, ${root.display(root.minimum)} to ${root.display(root.maximum)}`
function display(value: real): string {
if (value === 0 && root.zeroLabel !== "")
return root.zeroLabel;
@@ -145,6 +161,35 @@ Item {
root.pending = root.quantise(ratio);
commitTimer.restart();
}
activeFocusOnTab: true
Accessible.role: Accessible.Slider
Accessible.name: root.label
Accessible.description: root.detail === ""
? root.reading
: `${root.detail} ${root.reading}`
Accessible.focusable: true
Accessible.focused: slider.activeFocus
Accessible.onIncreaseAction: root.nudge(1)
Accessible.onDecreaseAction: root.nudge(-1)
Keys.onLeftPressed: root.nudge(-1)
Keys.onDownPressed: root.nudge(-1)
Keys.onRightPressed: root.nudge(1)
Keys.onUpPressed: root.nudge(1)
// Drawn only while the slider holds keyboard focus: transparent
// fill, so at rest there is nothing here at all.
Rectangle {
anchors.fill: parent
anchors.margins: -2
radius: 9
color: "transparent"
visible: slider.activeFocus
border.width: 2
border.color: Theme.accentSecondary
}
}
Text {