Improve dynamic widget settings forms

This commit is contained in:
Ryan Hughes
2026-05-18 23:46:21 -04:00
parent 61e7d2f307
commit efd46234f0
2 changed files with 46 additions and 30 deletions
+18 -7
View File
@@ -685,15 +685,26 @@ Item {
Layout.fillWidth: true Layout.fillWidth: true
} }
Loader { Flickable {
id: widgetDialogFormLoader id: widgetDialogScroll
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
sourceComponent: root.widgetDialogVisible ? formComponent(root.widgetDialogEntry.id || "") : null contentWidth: width
onLoaded: { contentHeight: widgetDialogFormLoader.item ? widgetDialogFormLoader.item.implicitHeight : 0
if (item && "entry" in item) item.entry = root.widgetDialogEntry clip: true
if (item && "fieldChanged" in item) { boundsBehavior: Flickable.StopAtBounds
item.fieldChanged.connect(function(key, value) { root.widgetDialogFieldChanged(key, value) }) flickableDirection: Flickable.VerticalFlick
ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded }
Loader {
id: widgetDialogFormLoader
width: widgetDialogScroll.width
sourceComponent: root.widgetDialogVisible ? formComponent(root.widgetDialogEntry.id || "") : null
onLoaded: {
if (item && "entry" in item) item.entry = root.widgetDialogEntry
if (item && "fieldChanged" in item) {
item.fieldChanged.connect(function(key, value) { root.widgetDialogFieldChanged(key, value) })
}
} }
} }
} }
+28 -23
View File
@@ -1,8 +1,8 @@
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls as QQC
import QtQuick.Layouts import QtQuick.Layouts
import qs.Commons import qs.Commons
import qs.Ui import qs.Ui as 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? }
@@ -62,6 +62,8 @@ Column {
} }
Loader { Loader {
width: parent.width
height: item ? item.implicitHeight : 0
sourceComponent: { sourceComponent: {
if (!modelData || !modelData.type) return stringField if (!modelData || !modelData.type) return stringField
switch (String(modelData.type)) { switch (String(modelData.type)) {
@@ -84,11 +86,12 @@ Column {
Component { Component {
id: stringField id: stringField
TextField { Ui.TextField {
property string fieldKey: "" property string fieldKey: ""
property var field: ({}) property var field: ({})
width: parent.width width: parent.width
foreground: root.foregroundColor foreground: root.foregroundColor
accent: Color.accent
font.family: root.fontFamilyName font.family: root.fontFamilyName
font.pixelSize: Style.font.body font.pixelSize: Style.font.body
text: root.currentValue(field) === undefined ? "" : String(root.currentValue(field)) text: root.currentValue(field) === undefined ? "" : String(root.currentValue(field))
@@ -98,43 +101,45 @@ Column {
Component { Component {
id: booleanField id: booleanField
CheckBox { Ui.Toggle {
property string fieldKey: "" property string fieldKey: ""
property var field: ({}) property var field: ({})
font.family: root.fontFamilyName width: parent.width
font.pixelSize: Style.font.body label: "Enabled"
text: field && field.label ? "" : "" foreground: root.foregroundColor
accent: Color.accent
fontFamily: root.fontFamilyName
checked: !!root.currentValue(field) checked: !!root.currentValue(field)
onToggled: if (fieldKey) root.fieldChanged(fieldKey, checked) onClicked: if (fieldKey) root.fieldChanged(fieldKey, !checked)
} }
} }
Component { Component {
id: enumField id: enumField
ComboBox { Ui.Dropdown {
property string fieldKey: "" property string fieldKey: ""
property var field: ({}) property var field: ({})
width: parent.width width: parent.width
font.family: root.fontFamilyName showLabel: false
font.pixelSize: Style.font.body foreground: root.foregroundColor
model: field && field.options ? field.options : [] accent: Color.accent
currentIndex: { fontFamily: root.fontFamilyName
var v = root.currentValue(field) options: field && field.options ? field.options : []
for (var i = 0; i < (field && field.options ? field.options.length : 0); i++) value: String(root.currentValue(field))
if (field.options[i] === v) return i onChanged: function(value) {
return 0 if (fieldKey) root.fieldChanged(fieldKey, value)
}
onActivated: function(index) {
if (fieldKey && field && field.options) root.fieldChanged(fieldKey, field.options[index])
} }
} }
} }
Component { Component {
id: integerField id: integerField
SpinBox { Ui.NumberField {
property string fieldKey: "" property string fieldKey: ""
property var field: ({}) property var field: ({})
foreground: root.foregroundColor
accent: Color.accent
fontFamily: root.fontFamilyName
from: field && field.min !== undefined ? field.min : 0 from: field && field.min !== undefined ? field.min : 0
to: field && field.max !== undefined ? field.max : 9999 to: field && field.max !== undefined ? field.max : 9999
stepSize: field && field.step !== undefined ? field.step : 1 stepSize: field && field.step !== undefined ? field.step : 1
@@ -143,7 +148,7 @@ Column {
var n = typeof v === "number" ? v : parseInt(String(v || 0), 10) var n = typeof v === "number" ? v : parseInt(String(v || 0), 10)
return isFinite(n) ? n : 0 return isFinite(n) ? n : 0
} }
onValueModified: if (fieldKey) root.fieldChanged(fieldKey, value) onModified: function(value) { if (fieldKey) root.fieldChanged(fieldKey, value) }
} }
} }
@@ -159,7 +164,7 @@ Column {
var n = typeof v === "number" ? v : parseFloat(String(v || 0)) var n = typeof v === "number" ? v : parseFloat(String(v || 0))
return isFinite(n) ? n : 0 return isFinite(n) ? n : 0
} }
Slider { QQC.Slider {
id: slider id: slider
width: parent.width - readout.width - Style.spacing.rowGap width: parent.width - readout.width - Style.spacing.rowGap
from: field && field.min !== undefined ? field.min : 0 from: field && field.min !== undefined ? field.min : 0