Files
qbz/crates/qbz-qt/qml/controls/SettingsFieldset.qml
T
vicrodh 7ca6c9fa80 fix(qt): a theme's options sit under its picker, boxed and collapsible
In Settings > Appearance the rows that exist only for one theme trailed the
whole THEME group: the Custom editor and the Auto source rows came after
Album header gradient, Compact header and Dynamic background. With a
Wallpaper background, Background image then ran straight into the Custom
editor and read as one of its options.

Each choice's options now follow their own picker inside a SettingsFieldset:
a bordered group with a header whose chevron folds it (> folded, v open).
The Custom and Auto theme options sit right under Theme, Custom starting at
"Start from current theme", and the Wallpaper background's Background image
sits under Dynamic background. The rows themselves are unchanged.

Each box keeps its folded state across restarts through settingsBool and
ui_prefs, the way the sidebar sections do (theme-custom-collapsed,
theme-auto-collapsed, ambient-options-collapsed; default open). Folding the
Custom box also closes an open color picker.

tst_settings_fieldset covers the rows inside the border, the header click
and keys, the settings below moving up, and a row click not toggling.

cc
2026-09-14 13:08:25 -06:00

102 lines
3.3 KiB
QML

// SettingsFieldset — a bordered, collapsible group of settings rows that
// belong to ONE control above them (the options of the selected theme).
//
// The border and the faint fill are what say "these rows are part of the
// same thing"; the header's chevron (> collapsed, v expanded) hides the body.
// The component does not own the collapsed state: the host passes the
// persisted value in and writes it back from `toggleRequested`, the same way
// the sidebar sections and the media-server panels keep theirs across
// restarts (settingsBool -> ui_prefs -> settingsJson).
//
// Rows go straight in as children; the body is a Column with a side inset,
// so a SettingRow still takes the full inner width.
import QtQuick
import com.blitzfc.qbz
import "../theme"
Rectangle {
id: root
property bool kioskHost: false
property string title: ""
property bool collapsed: false
signal toggleRequested()
default property alias content: body.data
QbzTheme { id: theme }
readonly property int inset: kioskHost ? 16 : 12
width: parent ? parent.width : 0
height: header.height + (collapsed ? 0 : body.height + inset)
radius: theme.radiusMd
color: theme.alphaTier(3)
border.width: 1
border.color: theme.borderMuted
Rectangle {
id: header
x: 1
y: 1
width: parent.width - 2
height: root.kioskHost ? 52 : 40
radius: theme.radiusMd
color: headerArea.containsMouse ? theme.elevatedHoverFill : "transparent"
activeFocusOnTab: true
border.width: activeFocus ? 2 : 0
border.color: theme.accent
Accessible.role: Accessible.Button
Accessible.name: root.title
Accessible.onPressAction: root.toggleRequested()
Keys.onPressed: function (event) {
if (!event.isAutoRepeat
&& (event.key === Qt.Key_Space
|| event.key === Qt.Key_Return
|| event.key === Qt.Key_Enter)) {
root.toggleRequested()
event.accepted = true
}
}
Row {
anchors.left: parent.left
anchors.leftMargin: root.inset - 2
anchors.verticalCenter: parent.verticalCenter
spacing: 8
QbzIcon {
anchors.verticalCenter: parent.verticalCenter
name: root.collapsed ? "chevron-right" : "chevron-down"
width: root.kioskHost ? 20 : 16
height: root.kioskHost ? 20 : 16
tintName: "secondary"
}
Text {
anchors.verticalCenter: parent.verticalCenter
text: root.title
color: theme.textPrimary
font.pixelSize: root.kioskHost ? theme.fontBody * 1.2 : theme.fontBody
font.weight: theme.weightSemibold
}
}
MouseArea {
id: headerArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onPressed: header.forceActiveFocus()
onClicked: root.toggleRequested()
}
}
Column {
id: body
visible: !root.collapsed
x: root.inset
y: header.y + header.height
width: root.width - 2 * root.inset
spacing: 4
}
}