Extract qs.Ui.TextField, migrate wifi passphrase + settings + dynamic form

This commit is contained in:
Ryan Hughes
2026-05-18 00:22:50 -04:00
parent 64115a9cb4
commit 1dd30e5c28
7 changed files with 120 additions and 53 deletions
@@ -57,6 +57,7 @@ Grouped by what they're for, not alphabetically.
| `CursorPill` | `PillButton` that participates in a panel's single-cursor model. Adds a `hovered(bool)` signal so the panel can update its cursor state on mouse enter/leave. Use for DNS-pill / header-pill / segmented-choice patterns. | | `CursorPill` | `PillButton` that participates in a panel's single-cursor model. Adds a `hovered(bool)` signal so the panel can update its cursor state on mouse enter/leave. Use for DNS-pill / header-pill / segmented-choice patterns. |
| `ChoiceButton` | A single button in a mutually-exclusive choice group (segmented control). `selected` uses accent fill+border; focus uses `Style.focusBorderColor` so keyboard nav reads differently from selection. | | `ChoiceButton` | A single button in a mutually-exclusive choice group (segmented control). `selected` uses accent fill+border; focus uses `Style.focusBorderColor` so keyboard nav reads differently from selection. |
| `Toggle` | Title + description + switch. Click anywhere on the row to flip; caller updates `checked` in response. | | `Toggle` | Title + description + switch. Click anywhere on the row to flip; caller updates `checked` in response. |
| `TextField` | Single-line input. Inherits from Qt Quick Controls `TextField` so all of its base API (text, placeholderText, accepted, validator, ...) is available. Adds `password: bool`, `foreground` / `accent` / `selectionTint` color overrides, and `horizontalPadding` / `verticalPadding` size knobs. Focus styling uses `Style.focusBorderColor` to match `Toggle` and `ChoiceButton`. |
| `PanelActionButton` | 22×22 right-edge action button (confirm, forget, unpair). `hoverColor` swaps between default foreground tint and urgent (red) tint. | | `PanelActionButton` | 22×22 right-edge action button (confirm, forget, unpair). `hoverColor` swaps between default foreground tint and urgent (red) tint. |
| `PanelSlider` | Volume/progress slider. Drag, click track, or wheel. `moved(value)` fires per change, `released(value)` once at end. (Named to avoid colliding with `QtQuick.Controls.Slider`.) | | `PanelSlider` | Volume/progress slider. Drag, click track, or wheel. `moved(value)` fires per change, `released(value)` once at end. (Named to avoid colliding with `QtQuick.Controls.Slider`.) |
| `WidgetButton` | Bar widget chrome — for the strip itself, not for inside panels. | | `WidgetButton` | Bar widget chrome — for the strip itself, not for inside panels. |
@@ -0,0 +1,49 @@
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 ChoiceButton 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
echoMode: password ? TextInput.Password : TextInput.Normal
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.activeFocus ? 0.08 : 0.04)
border.color: root.activeFocus
? Style.focusBorderColor
: Qt.rgba(root.foreground.r, root.foreground.g, root.foreground.b, 0.18)
border.width: root.activeFocus ? Style.focusBorderWidth : 1
radius: Style.cornerRadius
}
}
@@ -12,5 +12,6 @@ PanelSlider 1.0 PanelSlider.qml
PanelToolTip 1.0 PanelToolTip.qml PanelToolTip 1.0 PanelToolTip.qml
PillButton 1.0 PillButton.qml PillButton 1.0 PillButton.qml
PopupCard 1.0 PopupCard.qml PopupCard 1.0 PopupCard.qml
TextField 1.0 TextField.qml
Toggle 1.0 Toggle.qml Toggle 1.0 Toggle.qml
WidgetButton 1.0 WidgetButton.qml WidgetButton 1.0 WidgetButton.qml
@@ -1090,29 +1090,15 @@ iwctl known-networks list 2>/dev/null \\
anchors.right: connectPwBtn.left anchors.right: connectPwBtn.left
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.rightMargin: 6 anchors.rightMargin: 6
echoMode: TextInput.Password password: true
placeholderText: "Passphrase" placeholderText: "Passphrase"
font.family: root.bar.fontFamily font.family: root.bar.fontFamily
font.pixelSize: 12 font.pixelSize: 12
color: root.bar.foreground foreground: root.bar.foreground
selectionColor: Qt.rgba(root.bar.foreground.r, root.bar.foreground.g, root.bar.foreground.b, 0.35) horizontalPadding: 8
selectedTextColor: root.bar.foreground verticalPadding: 6
placeholderTextColor: Qt.darker(root.bar.foreground, 1.6)
leftPadding: 8
rightPadding: 8
topPadding: 6
bottomPadding: 6
enabled: !row.isBusy enabled: !row.isBusy
background: Rectangle {
color: Qt.rgba(root.bar.foreground.r, root.bar.foreground.g, root.bar.foreground.b, pwField.activeFocus ? 0.10 : 0.05)
border.color: pwField.activeFocus
? Qt.rgba(root.bar.foreground.r, root.bar.foreground.g, root.bar.foreground.b, 0.45)
: Qt.rgba(root.bar.foreground.r, root.bar.foreground.g, root.bar.foreground.b, 0.20)
border.width: 1
radius: 4
}
onAccepted: { onAccepted: {
if (!root.busy && row.net && text.length > 0) root.connectWithPassphrase(row.net.ssid, text) if (!root.busy && row.net && text.length > 0) root.connectWithPassphrase(row.net.ssid, text)
} }
@@ -699,6 +699,66 @@ Item {
} }
} }
// ---- TextField -----------------------------------------------------
Column {
width: parent.width
spacing: 8
Text {
text: "TextField"
color: root.foreground
font.family: root.fontFamily
font.pixelSize: 13
font.bold: true
}
Text {
text: "Single-line input. Inherits Qt Quick Controls TextField, swaps in the kit's focus chrome and selection styling. Toggle `password: true` for masked entry."
color: Qt.darker(root.foreground, 1.5)
font.family: root.fontFamily
font.pixelSize: 10
width: parent.width
wrapMode: Text.WordWrap
}
Rectangle {
width: parent.width
implicitHeight: tfCol.implicitHeight + 24
color: Qt.rgba(root.foreground.r, root.foreground.g, root.foreground.b, 0.04)
radius: 6
border.color: Qt.rgba(root.foreground.r, root.foreground.g, root.foreground.b, 0.10)
border.width: 1
Column {
id: tfCol
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: 14
anchors.rightMargin: 14
spacing: 10
TextField {
width: parent.width
placeholderText: "Type something"
foreground: root.foreground
accent: root.accent
font.family: root.fontFamily
font.pixelSize: 12
}
TextField {
width: parent.width
password: true
placeholderText: "Password"
foreground: root.foreground
accent: root.accent
font.family: root.fontFamily
font.pixelSize: 12
}
}
}
}
// ---- Toggle -------------------------------------------------------- // ---- Toggle --------------------------------------------------------
Column { Column {
width: parent.width width: parent.width
@@ -1210,28 +1210,13 @@ Item {
width: parent ? parent.width : 0 width: parent ? parent.width : 0
component CalendarField: TextField { component CalendarField: TextField {
id: calField
property string fieldKey: "" property string fieldKey: ""
width: parent.width
foreground: root.foreground
accent: root.accent
font.family: root.fontFamily font.family: root.fontFamily
font.pixelSize: 12 font.pixelSize: 12
width: parent.width
color: root.foreground
selectionColor: Qt.rgba(root.foreground.r, root.foreground.g, root.foreground.b, 0.35)
selectedTextColor: root.foreground
placeholderTextColor: Qt.darker(root.foreground, 1.6)
leftPadding: 10
rightPadding: 10
topPadding: 7
bottomPadding: 7
onEditingFinished: if (fieldKey) calForm.fieldChanged(fieldKey, text) onEditingFinished: if (fieldKey) calForm.fieldChanged(fieldKey, text)
background: Rectangle {
color: Qt.rgba(root.foreground.r, root.foreground.g, root.foreground.b,
calField.activeFocus ? 0.08 : 0.04)
border.color: calField.activeFocus
? Qt.rgba(root.foreground.r, root.foreground.g, root.foreground.b, 0.4)
: Qt.rgba(root.foreground.r, root.foreground.g, root.foreground.b, 0.18)
border.width: 1
}
} }
Text { Text {
@@ -1,6 +1,7 @@
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Layouts import QtQuick.Layouts
import qs.Ui
// Generic schema-driven settings form. The host panel passes: // Generic schema-driven settings form. The host panel passes:
// - schema: array of { key, label, type, defaultValue?, options?, min?, max?, step?, description? } // - schema: array of { key, label, type, defaultValue?, options?, min?, max?, step?, description? }
@@ -83,30 +84,14 @@ Column {
Component { Component {
id: stringField id: stringField
TextField { TextField {
id: stringControl
property string fieldKey: "" property string fieldKey: ""
property var field: ({}) property var field: ({})
width: parent.width width: parent.width
foreground: root.foregroundColor
font.family: root.fontFamilyName font.family: root.fontFamilyName
font.pixelSize: 12 font.pixelSize: 12
color: root.foregroundColor
selectionColor: Qt.rgba(root.foregroundColor.r, root.foregroundColor.g, root.foregroundColor.b, 0.35)
selectedTextColor: root.foregroundColor
placeholderTextColor: Qt.darker(root.foregroundColor, 1.6)
leftPadding: 10
rightPadding: 10
topPadding: 7
bottomPadding: 7
text: root.currentValue(field) === undefined ? "" : String(root.currentValue(field)) text: root.currentValue(field) === undefined ? "" : String(root.currentValue(field))
onEditingFinished: if (fieldKey) root.fieldChanged(fieldKey, text) onEditingFinished: if (fieldKey) root.fieldChanged(fieldKey, text)
background: Rectangle {
color: Qt.rgba(root.foregroundColor.r, root.foregroundColor.g, root.foregroundColor.b,
stringControl.activeFocus ? 0.08 : 0.04)
border.color: stringControl.activeFocus
? Qt.rgba(root.foregroundColor.r, root.foregroundColor.g, root.foregroundColor.b, 0.4)
: Qt.rgba(root.foregroundColor.r, root.foregroundColor.g, root.foregroundColor.b, 0.18)
border.width: 1
}
} }
} }