Files
arthur-os/shell/Ui/TextField.qml
T
Ryan Hughes b5f7ba02c2 Unify PillButton, CursorPill, ChoiceButton into qs.Ui.Button + ButtonGroup
The three components were three takes on the same shape \u2014 a clickable
rectangle with text/icon, a hot/hover state, an optional persistent
border, and an optional 'selected' or 'active' highlight. CursorPill
was a 30-line PillButton wrapper that added a hovered() signal;
ChoiceButton was effectively PillButton with selected: bool painting
an accent fill+border.

Collapse them into a single qs.Ui.Button. State flags compose
independently:

  hasCursor / hover         hot fill
  active                    persistent foreground-tint fill
  selected                  accent fill + accent border
  bordered: true            persistent 1px idle border (form primaries)
  focusable: true           Tab focus paints the accent ring
  pressed                   pressed fill

The hovered(bool) signal is now built-in, so CursorPill's wrapper is
unnecessary. ButtonGroup wraps a Row+Repeater for the form-style
'pick one of N' pattern; panel-cursor-driven cases still compose
Buttons directly in a Row with per-instance hasCursor wiring.

Theme tokens move into a new [style] section in shell.toml:

  border-width        = 1
  focus-border-width  = 3
  idle-border-alpha   = 0.4
  hot-fill-alpha      = 0.08
  selected-fill-alpha = 0.18
  pressed-fill-alpha  = 0.22
  focus-fill-alpha    = 0.22

Style.qml parses these out of the same shell.toml [font] / [bar]
already reads, and exposes pre-computed Style.hotFill / selectedFill /
pressedFill / idleBorderColor / selectedAccentFill / borderWidth +
the existing focusBorder* tokens. Themes that don't ship a [style]
section get the previous defaults unchanged.

Dev gallery consolidates three sections (PillButton, CursorPill,
ChoiceButton) into Button + ButtonGroup, with the cursor model
sections renamed accordingly.
2026-05-18 12:09:13 -04:00

62 lines
2.4 KiB
QML

import QtQuick
import QtQuick.Controls
import qs.Commons
// Single-line text input with the kit's focus + selection styling. Inherits
// from Qt Quick Controls TextField so the underlying type's API (text,
// placeholderText, accepted, editingFinished, validator, ...) is available
// to callers without re-exposing each property.
//
// Defaults bind to qs.Commons.Color so a caller with no theme overrides
// just works; foreground / accent / selectionTint can be overridden per
// instance. Focus styling uses Style.focusBorderColor (the same accent
// ring Toggle and Button paint) so keyboard cursor and form focus
// chrome stay consistent across the shell.
//
// Sizing is driven by font.pixelSize + verticalPadding. The default 30px
// implicitHeight fits dialog forms; inline callers (wifi's row-embedded
// passphrase prompt) drop verticalPadding to match a 22-26px row.
TextField {
id: root
property color foreground: Color.foreground
property color accent: Color.accent
property color selectionTint: Qt.rgba(foreground.r, foreground.g, foreground.b, 0.35)
property bool password: false
property real horizontalPadding: 10
property real verticalPadding: 7
// Panel-cursor flag. When true (and the field isn't already focused),
// the background paints the same accent ring as activeFocus so the
// panel's keyboard cursor lands here identically to a mouse hover.
// For mouse-enter/leave the consumer reads QQC TextField's inherited
// `hovered` property (via onHoveredChanged) — we don't add a sibling
// signal because the inherited property would shadow it.
property bool hasCursor: false
readonly property bool _focused: activeFocus || hasCursor
echoMode: password ? TextInput.Password : TextInput.Normal
font.family: Style.font.family
font.pixelSize: Style.font.body
color: foreground
selectionColor: selectionTint
selectedTextColor: foreground
placeholderTextColor: Qt.darker(foreground, 1.6)
leftPadding: horizontalPadding
rightPadding: horizontalPadding
topPadding: verticalPadding
bottomPadding: verticalPadding
background: Rectangle {
color: Qt.rgba(root.foreground.r, root.foreground.g, root.foreground.b,
root._focused ? 0.08 : 0.04)
border.color: root._focused
? Style.focusBorderColor
: Qt.rgba(root.foreground.r, root.foreground.g, root.foreground.b, 0.18)
border.width: root._focused ? Style.focusBorderWidth : 1
radius: Style.cornerRadius
}
}