Files
omarchycn/shell/Ui/ChoiceButton.qml
T
Ryan Hughes 42dee4d399 Standardize cursor chrome to fill-only across qs.Ui
CursorSurface defines the canonical cursor chrome: a tinted fill, no
border. Three components had inconsistent treatments that the recent
standardization pass left half-finished:

- PillButton kept a 1px foreground border on hot (cursor or hover)
  via a cursorBordered: true default.
- CursorPill specifically had to override cursorBordered: false to
  match the rest of the kit.
- ChoiceButton thickened its border to 2px on hasCursor, which mixed
  the cursor visual with the Tab-focus visual.

Drop the cursorBordered escape hatch from PillButton (no caller other
than CursorPill ever used it), drop CursorPill's now-redundant
override, and remove hasCursor from ChoiceButton's border.width
thickening. Update Toggle's class comment (it still claimed cursor
mirrored Tab focus, which f3ba5055 broke without updating the doc).

Now: hot/hasCursor = fill only, activeFocus = accent border ring,
selected/active = stronger fill or accent border per component
semantic. One canonical pattern across the kit.
2026-05-18 11:52:23 -04:00

81 lines
2.5 KiB
QML

import QtQuick
import qs.Commons
// A single button in a mutually-exclusive choice group (a Row of these
// makes a "segmented control"). Distinct from PillButton because it has
// a real `selected` state semantic — used for picking between options
// (bar position: top/bottom/left/right), not for momentary actions.
//
// Selected styling uses the accent fill+border; focus styling uses the
// Style.focusBorderColor outline so keyboard nav can land on a non-selected
// option without it reading as the chosen one. This separation matters in
// the settings panel and any future "pick one" UI.
Rectangle {
id: root
property string text: ""
property bool selected: false
// Panel-cursor flag. Same role as PillButton.hasCursor: panels that own
// their own cursor state bind this to drive the keyboard highlight
// separately from real activeFocus. Cursor renders as a fill only —
// CursorSurface is the canonical chrome — while Tab focus adds the
// accent border ring on top.
property bool hasCursor: false
property bool borderlessHighlight: false
property color foreground: Color.foreground
property color background: Color.background
property color accent: Color.accent
property string fontFamily: Style.font.family
property real fontSize: Style.font.body
signal clicked()
signal hovered(bool isHovered)
activeFocusOnTab: true
Keys.onReturnPressed: root.clicked()
Keys.onEnterPressed: root.clicked()
Keys.onSpacePressed: root.clicked()
implicitWidth: Math.max(56, label.implicitWidth + 22)
implicitHeight: 28
radius: Style.cornerRadius
color: selected
? Qt.rgba(accent.r, accent.g, accent.b, 0.18)
: ((mouse.containsMouse || hasCursor) ? Qt.rgba(foreground.r, foreground.g, foreground.b, 0.08) : background)
border.color: selected
? accent
: (activeFocus ? foreground : Qt.rgba(foreground.r, foreground.g, foreground.b, 0.4))
border.width: borderlessHighlight ? (activeFocus ? 2 : 0)
: (selected ? 2 : (activeFocus ? 2 : 1))
Behavior on color { ColorAnimation { duration: 100 } }
Text {
id: label
anchors.centerIn: parent
text: root.text
color: root.selected ? root.accent : root.foreground
font.family: root.fontFamily
font.pixelSize: root.fontSize
font.bold: root.selected
}
MouseArea {
id: mouse
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
root.forceActiveFocus()
root.clicked()
}
}
HoverHandler {
onHoveredChanged: root.hovered(hovered)
}
}