aboutsummaryrefslogtreecommitdiffstats
path: root/desktop/Settings.qml
diff options
context:
space:
mode:
Diffstat (limited to 'desktop/Settings.qml')
-rw-r--r--desktop/Settings.qml126
1 files changed, 126 insertions, 0 deletions
diff --git a/desktop/Settings.qml b/desktop/Settings.qml
new file mode 100644
index 0000000..a397105
--- /dev/null
+++ b/desktop/Settings.qml
@@ -0,0 +1,126 @@
+// Copyright (C) 2026 Danilo M. <danix@danix.xyz>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+import Quickshell
+import QtQuick
+
+// The settings window: a normal toplevel, not a layer surface, so Hyprland
+// tiles or floats it like any app. The drawer is the quick area; things set
+// once and left alone live here. It hosts the pages of the modules that
+// declare `settings: true`, from the same module list as the drawer, with a
+// list of them down the left.
+Scope {
+ id: root
+
+ property list<QtObject> modules
+ property bool open: false
+ property string page: ""
+
+ readonly property var pages: {
+ const out = [];
+ for (let i = 0; i < root.modules.length; i++)
+ if (root.modules[i].settings) out.push(root.modules[i]);
+ return out;
+ }
+ readonly property QtObject current: root.pages.find(m => m.name === root.page) ?? root.pages[0] ?? null
+
+ // An unknown or empty name opens the first page.
+ function show(name) { root.page = name; root.open = true; }
+ function close() { root.open = false; }
+
+ LazyLoader {
+ active: root.open
+
+ FloatingWindow {
+ title: "Settings"
+ implicitWidth: 900
+ implicitHeight: 640
+ color: Theme.base
+ onClosed: root.close()
+
+ Item {
+ anchors.fill: parent
+ focus: true
+ Keys.onEscapePressed: root.close()
+
+ ListView {
+ id: side
+ anchors { top: parent.top; left: parent.left; bottom: parent.bottom; margins: 12 }
+ width: 200
+ spacing: 4
+ model: root.pages
+
+ delegate: Rectangle {
+ id: entry
+ required property QtObject modelData
+ readonly property bool selected: root.current === modelData
+ width: side.width
+ height: 36
+ radius: 8
+ color: selected ? Qt.alpha(Theme.accent, 0.22)
+ : area.containsMouse ? Qt.alpha(Theme.text, 0.06) : "transparent"
+
+ Row {
+ anchors { left: parent.left; leftMargin: 10; verticalCenter: parent.verticalCenter }
+ spacing: 10
+ Text {
+ text: entry.modelData.icon
+ font { family: Theme.iconFamily; pixelSize: Theme.fontSize }
+ color: Theme.text
+ }
+ Text {
+ text: entry.modelData.label
+ font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 2 }
+ color: Theme.text
+ }
+ }
+
+ MouseArea {
+ id: area
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ onClicked: root.page = entry.modelData.name
+ }
+ }
+ }
+
+ Rectangle {
+ id: rule
+ anchors { top: parent.top; bottom: parent.bottom; left: side.right; leftMargin: 12 }
+ width: 1
+ color: Qt.alpha(Theme.text, 0.12)
+ }
+
+ Loader {
+ id: pageLoader
+ anchors { top: parent.top; right: parent.right; bottom: parent.bottom; left: rule.right; margins: 16 }
+ sourceComponent: root.current?.page ?? null
+
+ // The Page's back arrow and dismiss close the window;
+ // go() moves to another settings page by name.
+ onLoaded: {
+ if (item && item.back) item.back.connect(root.close);
+ if (item && item.dismiss) item.dismiss.connect(root.close);
+ if (item && item.go) item.go.connect(name => root.page = name);
+ }
+
+ Binding {
+ target: pageLoader.item
+ property: "icon"
+ value: root.current ? root.current.icon : ""
+ when: pageLoader.item !== null
+ }
+ }
+ }
+ }
+ }
+}