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
102 lines
3.3 KiB
QML
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
|
|
}
|
|
}
|