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.
81 lines
2.5 KiB
QML
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)
|
|
}
|
|
}
|