// Copyright (C) 2026 Danilo M. // // 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 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 } } } } } }