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
@@ -24,7 +24,28 @@ SettingRow {
detail: root.spec ? root.spec.detail : ""
controlWidth: Math.max(120, root.options.length * 92)
readonly property var currentOption:
root.options.find(option => option.value === root.current) ?? null
// Left and Right move one segment along and commit, which is what the
// segments already do under a click -- the arrows are just the other way to
// reach the same neighbour. It never wraps: running off the end of a
// segmented control silently landing on the far end is how a keyboard user
// sets something they did not mean to.
function stepChoice(delta: int): void {
if (root.options.length === 0)
return;
const at = root.options.findIndex(option => option.value === root.current);
const from = at < 0 ? 0 : at;
const next = Math.max(0, Math.min(root.options.length - 1, from + delta));
if (next === at)
return;
SystemSettings.commitPreference(root.setting, root.options[next].value);
}
Rectangle {
id: group
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
implicitWidth: segments.implicitWidth + 4
@@ -33,6 +54,35 @@ SettingRow {
color: Theme.alpha(Theme.fg, 0.07)
border.width: 0
activeFocusOnTab: true
Accessible.role: Accessible.ComboBox
Accessible.name: root.label
Accessible.description: {
const chosen = root.currentOption
? String(root.currentOption.label ?? "")
: "nothing selected";
return root.detail === "" ? chosen : `${root.detail} ${chosen}`;
}
Accessible.focusable: true
Accessible.focused: group.activeFocus
Keys.onLeftPressed: root.stepChoice(-1)
Keys.onUpPressed: root.stepChoice(-1)
Keys.onRightPressed: root.stepChoice(1)
Keys.onDownPressed: root.stepChoice(1)
// Focus ring only -- the strip keeps its borderless plate at rest.
Rectangle {
anchors.fill: parent
anchors.margins: -3
radius: 11
color: "transparent"
visible: group.activeFocus
border.width: 2
border.color: Theme.accentSecondary
}
Row {
id: segments
anchors.centerIn: parent
@@ -54,6 +104,13 @@ SettingRow {
border.width: 0
color: "transparent"
// Named individually so the reader says which option it is
// on, not just that a choice exists. Not a Tab stop: the
// strip is one stop and the arrows walk it.
Accessible.role: Accessible.RadioButton
Accessible.name: String(segment.modelData.label ?? "")
Accessible.checked: segment.selected
// The selected segment is the only place the prism appears
// in a row: blue leads into orchid, never orchid alone.
Rectangle {