Early Progress of SettingsWindow

This commit is contained in:
Ly-sec 2025-08-11 15:49:48 +02:00
parent 5543b58c3c
commit dc621647d7
14 changed files with 499 additions and 4 deletions

View file

@ -6,10 +6,6 @@ import Quickshell.Wayland
import qs.Services
import qs.Widgets
/*
An experiment/demo panel to tweaks widgets
*/
NLoader {
id: root

View file

@ -0,0 +1,179 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Wayland
import qs.Services
import qs.Widgets
import "Tabs" as Tabs
NLoader {
id: root
content: Component {
NPanel {
id: settingsPanel
readonly property real scaling: Scaling.scale(screen)
// Single source of truth for tabs
// Each tab points to a QML file path. The content stack simply loads the file via Loader.source.
property var tabsModel: [
{ icon: "tune", label: "General", source: "Tabs/General.qml" },
{ icon: "web_asset", label: "Bar", source: "Tabs/Bar.qml" },
{ icon: "schedule", label: "Time & Weather", source: "Tabs/TimeWeather.qml" },
{ icon: "videocam", label: "Screen Recorder", source: "Tabs/ScreenRecorder.qml" },
{ icon: "wifi", label: "Network", source: "Tabs/Network.qml" },
{ icon: "monitor", label: "Display", source: "Tabs/Display.qml" },
{ icon: "image", label: "Wallpaper", source: "Tabs/Wallpaper.qml" },
{ icon: "more_horiz", label: "Misc", source: "Tabs/Misc.qml" },
{ icon: "info", label: "About", source: "Tabs/About.qml" }
]
// Always default to the first tab (General) when the panel becomes visible
onVisibleChanged: function () {
if (visible) {
Qt.callLater(function () {
if (typeof stack !== 'undefined' && stack) {
stack.currentIndex = 0
}
})
}
}
// Ensure panel shows itself once created
Component.onCompleted: show()
Rectangle {
id: bgRect
color: Colors.backgroundPrimary
radius: Style.radiusLarge * scaling
border.color: Colors.backgroundTertiary
border.width: Math.max(1, Style.borderMedium * scaling)
layer.enabled: true
width: 1040 * scaling
height: 640 * scaling
anchors.centerIn: parent
// Prevent closing when clicking in the panel bg
MouseArea { anchors.fill: parent }
// Main two-pane layout
RowLayout {
anchors.fill: parent
anchors.margins: Style.marginLarge * scaling
spacing: Style.marginLarge * scaling
// Sidebar
Rectangle {
id: sidebar
Layout.preferredWidth: 260 * scaling
Layout.fillHeight: true
radius: Style.radiusMedium * scaling
color: Colors.backgroundSecondary
border.color: Colors.outline
border.width: Math.max(1, Style.borderThin * scaling)
ColumnLayout {
anchors.fill: parent
anchors.margins: Style.marginSmall * scaling
spacing: Style.marginSmall * scaling
Repeater {
id: sections
model: settingsPanel.tabsModel
delegate: Rectangle {
readonly property bool selected: index === stack.currentIndex
Layout.fillWidth: true
height: 44 * scaling
radius: Style.radiusSmall * scaling
color: selected ? Colors.highlight : "transparent"
border.color: Colors.outline
border.width: Math.max(1, Style.borderThin * scaling)
RowLayout {
anchors.fill: parent
anchors.leftMargin: Style.marginMedium * scaling
anchors.rightMargin: Style.marginMedium * scaling
spacing: Style.marginSmall * scaling
NText {
text: modelData.icon
font.family: "Material Symbols Outlined"
font.variableAxes: { "wght": (Font.Normal + Font.Bold) / 2.0 }
color: selected ? Colors.onAccent : Colors.textSecondary
}
NText { text: modelData.label; color: selected ? Colors.onAccent : Colors.textPrimary; Layout.fillWidth: true }
}
MouseArea { anchors.fill: parent; onClicked: stack.currentIndex = index }
}
}
}
}
// Content
Rectangle {
id: contentPane
Layout.fillWidth: true
Layout.fillHeight: true
radius: Style.radiusMedium * scaling
color: Colors.surface
border.color: Colors.outline
border.width: Math.max(1, Style.borderThin * scaling)
clip: true
// Content layout: header + divider + pages
ColumnLayout {
id: contentLayout
anchors.fill: parent
anchors.margins: Style.marginLarge * scaling
spacing: Style.marginSmall * scaling
// Header row
RowLayout {
id: headerRow
Layout.fillWidth: true
spacing: Style.marginSmall * scaling
NText {
text: settingsPanel.tabsModel[stack.currentIndex].label
font.weight: Style.fontWeightBold
color: Colors.textPrimary
Layout.fillWidth: true
}
NIconButton {
id: demoPanelToggle
icon: "close"
tooltipText: "Open demo panel"
Layout.alignment: Qt.AlignVCenter
onClicked: function () { settingsWindow.isLoaded = !settingsWindow.isLoaded }
}
}
NDivider { Layout.fillWidth: true }
// Stacked pages
StackLayout {
id: stack
Layout.fillWidth: true
Layout.fillHeight: true
currentIndex: 0
Component.onCompleted: currentIndex = 0
// Pages generated from tabsModel
Repeater {
model: settingsPanel.tabsModel
delegate: Loader {
active: index === stack.currentIndex
visible: active
source: modelData.source
}
}
}
}
}
}
}
}
}
}

View file

@ -0,0 +1,18 @@
import QtQuick
import QtQuick.Layouts
import qs.Services
import qs.Widgets
Item {
property real scaling: 1
anchors.fill: parent
ColumnLayout {
anchors.fill: parent
spacing: Style.marginMedium * scaling
NText { text: "About"; font.weight: Style.fontWeightBold; color: Colors.accentSecondary }
NText { text: "Coming soon"; color: Colors.textSecondary }
Item { Layout.fillHeight: true }
}
}

View file

@ -0,0 +1,19 @@
import QtQuick
import QtQuick.Layouts
import qs.Services
import qs.Widgets
Item {
// Optional scaling prop to match other tabs
property real scaling: 1
anchors.fill: parent
ColumnLayout {
anchors.fill: parent
spacing: Style.marginMedium * scaling
NText { text: "Bar"; font.weight: Style.fontWeightBold; color: Colors.accentSecondary }
NText { text: "Coming soon"; color: Colors.textSecondary }
Item { Layout.fillHeight: true }
}
}

View file

@ -0,0 +1,18 @@
import QtQuick
import QtQuick.Layouts
import qs.Services
import qs.Widgets
Item {
property real scaling: 1
anchors.fill: parent
ColumnLayout {
anchors.fill: parent
spacing: Style.marginMedium * scaling
NText { text: "Display"; font.weight: Style.fontWeightBold; color: Colors.accentSecondary }
NText { text: "Coming soon"; color: Colors.textSecondary }
Item { Layout.fillHeight: true }
}
}

View file

@ -0,0 +1,89 @@
import QtQuick
import QtQuick.Layouts
import qs.Services
import qs.Widgets
Item {
id: generalPage
// Public API
// Scaling factor provided by the parent settings window
property real scaling: 1
anchors.fill: parent
implicitWidth: parent ? parent.width : 0
implicitHeight: parent ? parent.height : 0
ColumnLayout {
anchors.fill: parent
anchors.margins: 0
spacing: Style.marginMedium * scaling
// Profile section
NText { text: "Profile"; font.weight: Style.fontWeightBold; color: Colors.accentSecondary }
RowLayout {
Layout.fillWidth: true
spacing: Style.marginMedium * scaling
// Avatar preview
Rectangle {
width: 40 * scaling
height: 40 * scaling
radius: 20 * scaling
color: Colors.surfaceVariant
border.color: Colors.outline
border.width: Math.max(1, Style.borderThin * scaling)
Image {
anchors.fill: parent
anchors.margins: 2 * scaling
source: Settings.data.general.avatarImage
fillMode: Image.PreserveAspectCrop
asynchronous: true
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 2 * scaling
NText { text: "Profile Image"; color: Colors.textPrimary; font.weight: Style.fontWeightBold }
NText { text: "Your profile picture displayed in various places throughout the shell"; color: Colors.textSecondary }
NTextBox {
text: Settings.data.general.avatarImage
placeholderText: "/home/user/.face"
Layout.fillWidth: true
onEditingFinished: Settings.data.general.avatarImage = text
}
}
}
NDivider { Layout.fillWidth: true; Layout.topMargin: Style.marginSmall * scaling; Layout.bottomMargin: Style.marginSmall * scaling }
// UI section
NText { text: "User Interface"; font.weight: Style.fontWeightBold; color: Colors.accentSecondary }
NToggle {
label: "Show Corners"
description: "Display rounded corners on the edge of the screen"
value: Settings.data.general.showScreenCorners
onToggled: function (v) { Settings.data.general.showScreenCorners = v }
}
NToggle {
label: "Show Dock"
description: "Display a dock at the bottom of the screen for quick access to applications"
value: Settings.data.general.showDock
onToggled: function (v) { Settings.data.general.showDock = v }
}
NToggle {
label: "Dim Desktop"
description: "Dim the desktop when panels or menus are open"
value: Settings.data.general.dimDesktop
onToggled: function (v) { Settings.data.general.dimDesktop = v }
}
Item { Layout.fillHeight: true }
}
}

View file

@ -0,0 +1,18 @@
import QtQuick
import QtQuick.Layouts
import qs.Services
import qs.Widgets
Item {
property real scaling: 1
anchors.fill: parent
ColumnLayout {
anchors.fill: parent
spacing: Style.marginMedium * scaling
NText { text: "Misc"; font.weight: Style.fontWeightBold; color: Colors.accentSecondary }
NText { text: "Coming soon"; color: Colors.textSecondary }
Item { Layout.fillHeight: true }
}
}

View file

@ -0,0 +1,18 @@
import QtQuick
import QtQuick.Layouts
import qs.Services
import qs.Widgets
Item {
property real scaling: 1
anchors.fill: parent
ColumnLayout {
anchors.fill: parent
spacing: Style.marginMedium * scaling
NText { text: "Network"; font.weight: Style.fontWeightBold; color: Colors.accentSecondary }
NText { text: "Coming soon"; color: Colors.textSecondary }
Item { Layout.fillHeight: true }
}
}

View file

@ -0,0 +1,18 @@
import QtQuick
import QtQuick.Layouts
import qs.Services
import qs.Widgets
Item {
property real scaling: 1
anchors.fill: parent
ColumnLayout {
anchors.fill: parent
spacing: Style.marginMedium * scaling
NText { text: "Screen Recorder"; font.weight: Style.fontWeightBold; color: Colors.accentSecondary }
NText { text: "Coming soon"; color: Colors.textSecondary }
Item { Layout.fillHeight: true }
}
}

View file

@ -0,0 +1,18 @@
import QtQuick
import QtQuick.Layouts
import qs.Services
import qs.Widgets
Item {
property real scaling: 1
anchors.fill: parent
ColumnLayout {
anchors.fill: parent
spacing: Style.marginMedium * scaling
NText { text: "Time & Weather"; font.weight: Style.fontWeightBold; color: Colors.accentSecondary }
NText { text: "Coming soon"; color: Colors.textSecondary }
Item { Layout.fillHeight: true }
}
}

View file

@ -0,0 +1,18 @@
import QtQuick
import QtQuick.Layouts
import qs.Services
import qs.Widgets
Item {
property real scaling: 1
anchors.fill: parent
ColumnLayout {
anchors.fill: parent
spacing: Style.marginMedium * scaling
NText { text: "Wallpaper"; font.weight: Style.fontWeightBold; color: Colors.accentSecondary }
NText { text: "Coming soon"; color: Colors.textSecondary }
Item { Layout.fillHeight: true }
}
}

View file

@ -10,6 +10,8 @@ NBox {
id: root
readonly property real scaling: Scaling.scale(screen)
// Hold a single instance of the Settings window (root is NLoader)
property var settingsWindow: null
Layout.fillWidth: true
// Height driven by content
@ -71,6 +73,23 @@ NBox {
NIconButton {
icon: "settings"
sizeMultiplier: 0.9
onClicked: function () {
if (!root.settingsWindow) {
const comp = Qt.createComponent("../Settings/SettingsWindow.qml")
if (comp.status === Component.Ready) {
root.settingsWindow = comp.createObject(root)
} else {
comp.statusChanged.connect(function () {
if (comp.status === Component.Ready) {
root.settingsWindow = comp.createObject(root)
}
})
}
}
if (root.settingsWindow) {
root.settingsWindow.isLoaded = !root.settingsWindow.isLoaded
}
}
}
NIconButton {
icon: "power_settings_new"