import QtQuick import Qt.labs.folderlistmodel import Quickshell import Quickshell.Bluetooth import Quickshell.Io import Quickshell.Services.Pipewire import "../.." Item { id: root width: parent ? parent.width : 1280 height: parent ? parent.height : 820 focus: true /* ------------------------------ PIXEL CONSTANTS (DO NOT TOUCH) ------------------------------ */ property int menuLeft: 64 property int menuTop: 140 property int lineHeight: 38 + 40 + 1 property int visibleRows: Math.max(1, Math.floor((height - menuTop - 64) / lineHeight)) property int scrollOffset: 0 property int nameFontSize: 32 property int stateFontSize: 28 property int stateColumnX: 824 property int soulOffsetX: -36 - 32 property int soulOffsetY: -26 /* ------------------------------ */ property ShellStateManager manager: null property int activeSelection: 0 property bool inBluetoothMenu: false property bool inWallpaperMenu: false property bool isSelected: false property string wallpapersDir: (Quickshell.env("HOME") || "") + "/Pictures/Wallpapers" property string wallpaperCachePath: (Quickshell.env("HOME") || "") + "/.cache/.wallpaper" property string currentWallpaperPath: "" function clamp(v, lo, hi) { return Math.max(lo, Math.min(hi, v)); } function menuLength() { if (root.inBluetoothMenu && bluetoothRepeater) return bluetoothRepeater.count; if (root.inWallpaperMenu && wallpaperFolderModel) return wallpaperFolderModel.count; if (!menuModel) return 0; if (typeof menuModel.count === "function") return menuModel.count(); if (menuModel.count !== undefined) return menuModel.count; if (menuModel.length !== undefined) return menuModel.length; return 0; } function menuAt(index) { if (!menuModel) return null; if (menuModel.get) return menuModel.get(index); if (menuModel.length !== undefined) return menuModel[index]; return null; } function wrapIndex(i) { const length = menuLength(); if (length === 0) return 0; return (i + length) % length; } function currentAction() { if (root.inBluetoothMenu || root.inWallpaperMenu) return null; return menuLength() > 0 ? menuAt(activeSelection) : null; } function clampSelection() { const length = menuLength(); if (length === 0) { activeSelection = 0; scrollOffset = 0; return; } activeSelection = clamp(activeSelection, 0, length - 1); const maxOffset = Math.max(0, length - visibleRows); scrollOffset = clamp(scrollOffset, 0, maxOffset); } function ensureVisible() { if (!root.inWallpaperMenu) return; const length = menuLength(); if (length === 0) { scrollOffset = 0; return; } if (activeSelection < scrollOffset) scrollOffset = activeSelection; else if (activeSelection >= scrollOffset + visibleRows) scrollOffset = Math.max(0, activeSelection - visibleRows + 1); } function bluetoothDisplayName(device) { if (!device) return ""; if (device.name && device.name.length > 0) return device.name; return device.deviceName || ""; } function bluetoothDisplayState(device) { if (!device) return ""; // dont change symbols return device.connected ? "✓" : ""; } function bluetoothDeviceAt(index) { const item = bluetoothRepeater.itemAt(index); if (!item) return null; return item.device || null; } function trimText(text) { return (text || "").replace(/^\s+|\s+$/g, ""); } function normalizedPath(path) { var value = trimText(path); if (value.indexOf("file://") === 0) value = value.slice(7); return value; } function wallpaperNameAt(index) { if (!wallpaperFolderModel || index < 0 || index >= wallpaperFolderModel.count) return ""; var name = wallpaperFolderModel.get(index, "fileName") || ""; return name.replace(/\.[^/.]+$/, ""); } function wallpaperPathAt(index) { if (!wallpaperFolderModel || index < 0 || index >= wallpaperFolderModel.count) return ""; return wallpaperFolderModel.get(index, "filePath") || ""; } function currentWallpaperIndex() { var current = normalizedPath(currentWallpaperPath); if (!current || !wallpaperFolderModel) return -1; for (var i = 0; i < wallpaperFolderModel.count; i++) { if (normalizedPath(wallpaperPathAt(i)) === current) return i; } return -1; } function refreshCurrentWallpaper() { root.currentWallpaperPath = normalizedPath(wallpaperFile.text()); } function applyWallpaper(path) { var normalized = normalizedPath(path); if (!normalized || normalized.length === 0) return; root.currentWallpaperPath = normalized; wallpaperFile.setText(normalized + "\n"); wallpaperApplyProcess.running = false; wallpaperApplyProcess.environment = { "WALLPAPER_PATH": normalized }; wallpaperApplyProcess.command = ["bash", "-lc", "rm -rf \"$HOME/.cache/wal\"; if [[ \"$(hostname)\" != \"gentoo\" ]]; then swww img \"$WALLPAPER_PATH\" --transition-type none; else HYPRPAPER_PID=\"$(pidof hyprpaper)\"; if [ ${#HYPRPAPER_PID} -lt 1 ]; then hyprctl dispatch exec hyprpaper; sleep 1; fi; hyprctl hyprpaper unload all; hyprctl hyprpaper preload \"$WALLPAPER_PATH\"; hyprctl hyprpaper wallpaper ,\"$WALLPAPER_PATH\"; fi"]; wallpaperApplyProcess.running = true; } PwObjectTracker { objects: [Pipewire.defaultAudioSink] } property int bluetoothActionIndex: 1 property int wallpaperActionIndex: 2 property var actions: [ { name: "Master Volume", arr: function (dir) { const sink = Pipewire.defaultAudioSink; if (!sink || !sink.audio) return; const step = 0.05; sink.audio.muted = false; sink.audio.volume = clamp(sink.audio.volume + dir * step, 0, 1); }, getState: function () { const sink = Pipewire.defaultAudioSink; if (!sink || !sink.audio) return "—"; return Math.round(sink.audio.volume * 100) + "%"; } }, { name: "Bluetooth", ent: function () { root.inBluetoothMenu = true; root.inWallpaperMenu = false; root.isSelected = false; root.activeSelection = 0; root.clampSelection(); }, getState: function () { return ""; } }, { name: "Wallpaper", ent: function () { root.inWallpaperMenu = true; root.inBluetoothMenu = false; root.isSelected = false; var currentIndex = root.currentWallpaperIndex(); root.activeSelection = currentIndex >= 0 ? currentIndex : 0; root.scrollOffset = 0; root.clampSelection(); root.ensureVisible(); }, getState: function () { return ""; } } ] property var menuModel: root.inBluetoothMenu ? Bluetooth.devices : (root.inWallpaperMenu ? wallpaperFolderModel : actions) FolderListModel { id: wallpaperFolderModel folder: "file://" + root.wallpapersDir nameFilters: ["*.jpg", "*.jpeg", "*.png", "*.webp", "*.bmp", "*.gif"] showDirs: false showDotAndDotDot: false sortField: FolderListModel.Name sortReversed: false onCountChanged: { if (root.inWallpaperMenu) { root.clampSelection(); root.ensureVisible(); } } } FileView { id: wallpaperFile path: root.wallpaperCachePath watchChanges: true onLoaded: root.refreshCurrentWallpaper() onFileChanged: reload() onLoadFailed: root.currentWallpaperPath = "" } Process { id: wallpaperApplyProcess } Connections { target: Bluetooth.devices ignoreUnknownSignals: true function onCountChanged() { if (root.inBluetoothMenu) root.clampSelection(); } function onModelReset() { if (root.inBluetoothMenu) root.clampSelection(); } function onRowsInserted() { if (root.inBluetoothMenu) root.clampSelection(); } function onRowsRemoved() { if (root.inBluetoothMenu) root.clampSelection(); } } Connections { target: wallpaperFolderModel ignoreUnknownSignals: true function onModelReset() { if (root.inWallpaperMenu) { root.clampSelection(); root.ensureVisible(); } } function onRowsInserted() { if (root.inWallpaperMenu) { root.clampSelection(); root.ensureVisible(); } } function onRowsRemoved() { if (root.inWallpaperMenu) { root.clampSelection(); root.ensureVisible(); } } } Text { text: root.inBluetoothMenu ? "BLUETOOTH" : (root.inWallpaperMenu ? "WALLPAPER" : "CONFIG") font.family: "8bitoperator JVE" font.pixelSize: 71 renderType: Text.NativeRendering font.hintingPreference: Font.PreferNoHinting smooth: false antialiasing: false anchors.horizontalCenter: parent.horizontalCenter color: "#ffffff" y: 32 } Repeater { id: bluetoothRepeater model: root.menuModel delegate: Item { width: root.width height: lineHeight x: 0 y: menuTop + (root.inWallpaperMenu ? (index - root.scrollOffset) * lineHeight : index * lineHeight) visible: !root.inWallpaperMenu || (index >= root.scrollOffset && index < root.scrollOffset + root.visibleRows) property var device: root.inBluetoothMenu ? modelData : null Image { source: "./soul.png" width: 36 height: 36 x: 182 y: 8 + 14 visible: root.activeSelection == index } Text { x: 239 y: 0 text: root.inBluetoothMenu ? root.bluetoothDisplayName(modelData) : (root.inWallpaperMenu ? root.wallpaperNameAt(index) : modelData.name) width: root.width - 239 - (root.inWallpaperMenu ? 96 : 300) font.family: "8bitoperator JVE" font.pixelSize: 71 font.letterSpacing: 1 renderType: Text.NativeRendering font.hintingPreference: Font.PreferNoHinting smooth: false antialiasing: false wrapMode: Text.NoWrap elide: Text.ElideRight color: (root.activeSelection == index && (root.isSelected == true || root.inBluetoothMenu || root.inWallpaperMenu)) ? "#fefe00" : "#ffffff" } // Option state Text { x: menuLeft + stateColumnX y: 4 visible: !root.inWallpaperMenu text: root.inBluetoothMenu ? root.bluetoothDisplayState(modelData) : (modelData.getState ? modelData.getState() : "") font.family: "8bitoperator JVE" font.pixelSize: 71 font.letterSpacing: 1 renderType: Text.NativeRendering font.hintingPreference: Font.PreferNoHinting smooth: false antialiasing: false color: (root.activeSelection == index && (root.isSelected == true || root.inBluetoothMenu || root.inWallpaperMenu)) ? "#fefe00" : "#ffffff" } } } /* ------------------------------ INPUT HANDLING ------------------------------ */ function handleKey(key) { switch (key) { case Qt.Key_Up: if (root.inBluetoothMenu || root.inWallpaperMenu || root.isSelected === false) { activeSelection = wrapIndex(activeSelection - 1); root.ensureVisible(); } return true; case Qt.Key_Down: if (root.inBluetoothMenu || root.inWallpaperMenu || root.isSelected === false) { activeSelection = wrapIndex(activeSelection + 1); root.ensureVisible(); } return true; case Qt.Key_Left: { const a = currentAction(); if (a && a.arr && root.isSelected === true) a.arr(-1); return true; } case Qt.Key_Right: { const a = currentAction(); if (a && a.arr && root.isSelected === true) a.arr(1); return true; } case Qt.Key_Z: case Qt.Key_Return: case Qt.Key_Enter: { if (root.inBluetoothMenu) { const device = bluetoothDeviceAt(activeSelection); console.log(root.inBluetoothMenu, activeSelection, device); if (device) { if (!device.connected) { device.connect(); } else { device.disconnect(); } // device.connected = !device.connected; } } else if (root.inWallpaperMenu) { const wallpaperPath = wallpaperPathAt(activeSelection); if (wallpaperPath && wallpaperPath.length > 0) root.applyWallpaper(wallpaperPath); } else { const a = currentAction(); if (a && a.ent) { a.ent(); } else { root.isSelected = !root.isSelected; } } return true; } case Qt.Key_X: case Qt.Key_Shift: case Qt.Key_Escape: if (root.inWallpaperMenu) { root.inWallpaperMenu = false; root.isSelected = false; root.scrollOffset = 0; root.activeSelection = root.wallpaperActionIndex; root.clampSelection(); } else if (root.inBluetoothMenu) { root.inBluetoothMenu = false; root.isSelected = false; root.activeSelection = root.bluetoothActionIndex; root.clampSelection(); } else if (root.isSelected === true) { root.isSelected = false; } else { if (manager && manager.closeQuickSettings) { manager.closeQuickSettings(); } } return true; } return false; } Component.onCompleted: { root.activeSelection = 0; root.isSelected = false; root.inBluetoothMenu = false; root.inWallpaperMenu = false; root.scrollOffset = 0; root.refreshCurrentWallpaper(); ShellInputManager.registerHandler("quickSettings", handleKey); } Component.onDestruction: { ShellInputManager.unregisterHandler("quickSettings"); } }