Add qs.Ui.NumberField; migrate weather + spacer settings
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls as QQC
|
||||
import qs.Commons
|
||||
|
||||
Column {
|
||||
id: root
|
||||
|
||||
property string label: ""
|
||||
property int value: 0
|
||||
property int from: 0
|
||||
property int to: 100
|
||||
property int stepSize: 1
|
||||
property color foreground: Color.foreground
|
||||
property color accent: Color.accent
|
||||
property string fontFamily: "JetBrainsMono Nerd Font"
|
||||
property real fontSize: 12
|
||||
property real fieldWidth: 120
|
||||
property bool hasCursor: false
|
||||
property alias field: spin
|
||||
|
||||
signal modified(int value)
|
||||
signal hovered(bool on)
|
||||
|
||||
spacing: 6
|
||||
|
||||
Text {
|
||||
visible: root.label !== ""
|
||||
text: root.label
|
||||
color: Qt.darker(root.foreground, 1.4)
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: 11
|
||||
}
|
||||
|
||||
QQC.SpinBox {
|
||||
id: spin
|
||||
width: root.fieldWidth
|
||||
from: root.from
|
||||
to: root.to
|
||||
stepSize: root.stepSize
|
||||
value: root.value
|
||||
editable: true
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: root.fontSize
|
||||
|
||||
onValueModified: root.modified(value)
|
||||
|
||||
background: Rectangle {
|
||||
readonly property bool _hot: spin.activeFocus || (root.hasCursor && !spin.activeFocus)
|
||||
color: Qt.rgba(root.foreground.r, root.foreground.g, root.foreground.b, _hot ? 0.10 : 0.05)
|
||||
border.color: _hot
|
||||
? Style.focusBorderColor
|
||||
: Qt.rgba(root.foreground.r, root.foreground.g, root.foreground.b, 0.3)
|
||||
border.width: _hot ? Style.focusBorderWidth : 1
|
||||
radius: Style.cornerRadius
|
||||
|
||||
HoverHandler {
|
||||
onHoveredChanged: root.hovered(hovered)
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: TextInput {
|
||||
text: spin.displayText
|
||||
font: spin.font
|
||||
color: root.foreground
|
||||
selectionColor: Qt.rgba(root.foreground.r, root.foreground.g, root.foreground.b, 0.35)
|
||||
selectedTextColor: root.foreground
|
||||
horizontalAlignment: Qt.AlignHCenter
|
||||
verticalAlignment: Qt.AlignVCenter
|
||||
readOnly: !spin.editable
|
||||
validator: spin.validator
|
||||
inputMethodHints: Qt.ImhFormattedNumbersOnly
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,6 +58,7 @@ Grouped by what they're for, not alphabetically.
|
||||
| `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. `rounded` auto-detects from `Style.cornerRadius` so the switch is a pill on round-corners themes and square on sharp; override per-instance to force one or the other. |
|
||||
| `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`. `hasCursor` paints the same focus ring so a panel cursor lands on the field identically. For hover wiring use QQC TextField's inherited `hovered` property (via `onHoveredChanged`) — the sibling signal name would shadow it. |
|
||||
| `NumberField` | Labeled integer spin box. `label` renders above the field; `from`/`to`/`stepSize`/`value` constrain and seed the value; `modified(int)` fires on each commit. Theme-aware focus ring shared with `TextField`, and `hasCursor` + `hovered(bool)` wiring for the panel-cursor model. Wraps Qt Quick Controls `SpinBox`; access it via the `field` alias if you need to call `forceActiveFocus()` from a parent. |
|
||||
| `Dropdown` | Single-select dropdown with a themed popup (no platform-native ComboBox chrome). `options` accepts `string[]` or `[{ value, label }]`. Keyboard: Tab to focus trigger, Enter/Space opens, j/k or arrows walk options, Enter selects. `hasCursor` paints the focus ring on the trigger; emits `hovered(bool)`. `popupOpen` plus `open()` / `close()` / `toggle()` let a parent panel suspend its own key catcher while the popup owns keys. |
|
||||
| `SearchableDropdown` | `Dropdown` with an embedded search field at the top of the popup that filters options as you type. Use when the option count is high enough that scanning is friction (e.g. bar settings "+ Add widget"). Options can also carry a `description` string that the filter matches against. Same `hasCursor` / `popupOpen` / `open()` / `close()` / `toggle()` / `hovered(bool)` surface as `Dropdown`. |
|
||||
| `PanelActionButton` | 22×22 right-edge action button (confirm, forget, unpair). `hoverColor` swaps between default foreground tint and urgent (red) tint. `focusable: true` enables Tab-focus with an accent ring — used for the bar settings widget-card row controls. `hasCursor: true` paints the hover fill so a panel cursor can land on the button directly when it isn't living inside a `CursorSurface` row; emits `hovered(bool)`. |
|
||||
|
||||
@@ -5,6 +5,7 @@ CursorPill 1.0 CursorPill.qml
|
||||
CursorSurface 1.0 CursorSurface.qml
|
||||
Dropdown 1.0 Dropdown.qml
|
||||
KeyboardPanel 1.0 KeyboardPanel.qml
|
||||
NumberField 1.0 NumberField.qml
|
||||
PanelActionButton 1.0 PanelActionButton.qml
|
||||
PanelKeyCatcher 1.0 PanelKeyCatcher.qml
|
||||
PanelSectionHeader 1.0 PanelSectionHeader.qml
|
||||
|
||||
@@ -90,11 +90,12 @@ Item {
|
||||
property bool toggleSquareOn: false
|
||||
property string dropdownDemoValue: "calendar"
|
||||
property string searchableDemoValue: ""
|
||||
property int numberDemoValue: 15
|
||||
|
||||
readonly property var visibleSections: [
|
||||
"cursor-surface", "pill-button", "cursor-pill", "panel-action-button",
|
||||
"panel-tool-tip", "slider", "choice-button", "text-field", "toggle",
|
||||
"dropdown", "searchable-dropdown", "composed"
|
||||
"panel-tool-tip", "slider", "choice-button", "text-field", "number-field",
|
||||
"toggle", "dropdown", "searchable-dropdown", "composed"
|
||||
]
|
||||
|
||||
function sectionCount(section) {
|
||||
@@ -107,6 +108,7 @@ Item {
|
||||
case "slider": return 1
|
||||
case "choice-button": return 4
|
||||
case "text-field": return 2
|
||||
case "number-field": return 1
|
||||
case "toggle": return 2
|
||||
case "dropdown": return 1
|
||||
case "searchable-dropdown": return 1
|
||||
@@ -211,6 +213,10 @@ Item {
|
||||
else demoPasswordField.forceActiveFocus()
|
||||
return
|
||||
}
|
||||
if (focusSection === "number-field") {
|
||||
numberDemo.field.forceActiveFocus()
|
||||
return
|
||||
}
|
||||
// pill / panel-action-button / cursor-surface / composed: nothing to
|
||||
// mutate in a demo, but real consumers would call their clicked().
|
||||
}
|
||||
@@ -1082,6 +1088,57 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
// ---- NumberField ---------------------------------------------------
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: 8
|
||||
|
||||
Text {
|
||||
text: "NumberField"
|
||||
color: root.foreground
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: 13
|
||||
font.bold: true
|
||||
}
|
||||
Text {
|
||||
text: "Labeled spin box for integer settings. Up/down arrows step the value; the field accepts typed input. Pair with `from`/`to`/`stepSize` to constrain range."
|
||||
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: numberDemo.implicitHeight + 24
|
||||
color: Qt.rgba(root.foreground.r, root.foreground.g, root.foreground.b, 0.04)
|
||||
border.color: Qt.rgba(root.foreground.r, root.foreground.g, root.foreground.b, 0.12)
|
||||
border.width: 1
|
||||
radius: Style.cornerRadius
|
||||
|
||||
NumberField {
|
||||
id: numberDemo
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.leftMargin: 12
|
||||
label: "Auto-refresh interval (minutes)"
|
||||
from: 1
|
||||
to: 1440
|
||||
value: root.numberDemoValue
|
||||
foreground: root.foreground
|
||||
accent: root.accent
|
||||
fontFamily: root.fontFamily
|
||||
hasCursor: root.focusSection === "number-field" && root.selectedIndex === 0
|
||||
onModified: function(v) { root.numberDemoValue = v }
|
||||
onHovered: function(on) {
|
||||
if (on) { root.focusSection = "number-field"; root.selectedIndex = 0 }
|
||||
}
|
||||
onHasCursorChanged: if (hasCursor) root.ensureCursorVisible(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Toggle --------------------------------------------------------
|
||||
Column {
|
||||
width: parent.width
|
||||
|
||||
@@ -1088,18 +1088,15 @@ Item {
|
||||
spacing: 8
|
||||
width: parent ? parent.width : 0
|
||||
|
||||
Text {
|
||||
text: "Size (pixels)"
|
||||
color: Qt.darker(root.foreground, 1.4)
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: 11
|
||||
}
|
||||
|
||||
SpinBox {
|
||||
NumberField {
|
||||
label: "Size (pixels)"
|
||||
from: 0
|
||||
to: 256
|
||||
value: spacerForm.entry.size !== undefined ? spacerForm.entry.size : 12
|
||||
onValueModified: spacerForm.fieldChanged("size", value)
|
||||
foreground: root.foreground
|
||||
accent: root.accent
|
||||
fontFamily: root.fontFamily
|
||||
onModified: function(v) { spacerForm.fieldChanged("size", v) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1171,18 +1168,15 @@ Item {
|
||||
spacing: 8
|
||||
width: parent ? parent.width : 0
|
||||
|
||||
Text {
|
||||
text: "Auto-refresh interval (minutes)"
|
||||
color: Qt.darker(root.foreground, 1.4)
|
||||
font.family: root.fontFamily
|
||||
font.pixelSize: 11
|
||||
}
|
||||
|
||||
SpinBox {
|
||||
NumberField {
|
||||
label: "Auto-refresh interval (minutes)"
|
||||
from: 1
|
||||
to: 1440
|
||||
value: weatherForm.entry.refreshMinutes !== undefined ? weatherForm.entry.refreshMinutes : 15
|
||||
onValueModified: weatherForm.fieldChanged("refreshMinutes", value)
|
||||
foreground: root.foreground
|
||||
accent: root.accent
|
||||
fontFamily: root.fontFamily
|
||||
onModified: function(v) { weatherForm.fieldChanged("refreshMinutes", v) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user