// A segmented choice that is NOT schema-bound. // // ChoiceRow reads its options from the preference schema. This one is handed // them, for choices that describe system state rather than a Panama setting. import QtQuick import qs.config SettingRow { id: root // [{ value, label }] property var options: [] property var value: null property bool enabled: true signal selected(value: var) controlWidth: Math.max(150, root.options.length * 92) readonly property var currentOption: root.options.find(option => option.value === root.value) ?? null // One segment along, never wrapping -- the same neighbour a click would // have picked, asked for in the same way. function stepChoice(delta: int): void { if (!root.enabled || root.options.length === 0) return; const at = root.options.findIndex(option => option.value === root.value); const from = at < 0 ? 0 : at; const next = Math.max(0, Math.min(root.options.length - 1, from + delta)); if (next === at) return; root.selected(root.options[next].value); } // Sibling of the strip rather than a child of it: a Rectangle inside a Row // would be laid out as one more segment. Rectangle { anchors.fill: strip anchors.margins: -3 radius: 12 z: -1 color: "transparent" visible: strip.activeFocus border.width: 2 border.color: Theme.accentSecondary } Row { id: strip anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter spacing: 6 opacity: root.enabled ? 1 : 0.45 activeFocusOnTab: root.enabled 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: root.enabled Accessible.focused: strip.activeFocus Keys.onLeftPressed: root.stepChoice(-1) Keys.onUpPressed: root.stepChoice(-1) Keys.onRightPressed: root.stepChoice(1) Keys.onDownPressed: root.stepChoice(1) Repeater { model: root.options delegate: Rectangle { id: segment required property var modelData readonly property bool current: root.value === segment.modelData.value width: Math.max(84, segmentLabel.implicitWidth + 22) height: 30 radius: 9 color: segment.current ? Theme.alpha(Theme.accent, 0.22) : Theme.alpha(Theme.fg, segmentMouse.containsMouse ? 0.12 : 0.06) border.width: 1 border.color: segment.current ? Theme.alpha(Theme.accent, 0.5) : Theme.alpha(Theme.fg, 0.08) // Named individually so the reader says which option it is on. // 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.current Text { id: segmentLabel anchors.centerIn: parent text: String(segment.modelData.label ?? "") color: segment.current ? Theme.fg : Theme.fgDim font.family: Theme.fontFamily font.pixelSize: Theme.fontSizeSmall font.weight: segment.current ? Font.DemiBold : Font.Medium } MouseArea { id: segmentMouse anchors.fill: parent hoverEnabled: true enabled: root.enabled && !segment.current cursorShape: Qt.PointingHandCursor onClicked: root.selected(segment.modelData.value) } } } } }