// 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 Quickshell.Widgets import QtQuick import ".." import "Logic.js" as Logic // Output and input level with mute, and the way into the drawer's sound // page. Device pickers and per-app volume stay on that page. Column { id: panel // The sound module's Service: sink, source, tracked by PwObjectTracker. required property QtObject sound signal openDrawer() spacing: 12 Repeater { model: [{ label: "Output", input: false }, { label: "Input", input: true }] delegate: Row { id: row required property var modelData readonly property var audio: (modelData.input ? panel.sound.source : panel.sound.sink)?.audio ?? null width: panel.width spacing: 10 IconImage { id: muteIcon anchors.verticalCenter: parent.verticalCenter implicitSize: 18 source: Quickshell.iconPath(row.modelData.input ? (row.audio?.muted ? "microphone-sensitivity-muted" : "audio-input-microphone") : Logic.volumeIcon(row.audio?.volume ?? 0, row.audio?.muted ?? false), true) MouseArea { anchors.fill: parent enabled: row.audio !== null cursorShape: Qt.PointingHandCursor onClicked: row.audio.muted = !row.audio.muted } } Rectangle { id: track anchors.verticalCenter: parent.verticalCenter width: row.width - muteIcon.width - pct.width - row.spacing * 2 height: 8 radius: 4 color: Theme.surface Rectangle { height: parent.height radius: parent.radius width: parent.width * Math.min(1, row.audio?.volume ?? 0) color: row.audio?.muted ? Theme.red : Theme.accent opacity: row.audio?.muted ? 0.5 : 1 } MouseArea { anchors.fill: parent enabled: row.audio !== null preventStealing: true cursorShape: Qt.PointingHandCursor onPressed: mouse => set(mouse.x) onPositionChanged: mouse => { if (pressed) set(mouse.x); } function set(x) { row.audio.volume = Math.max(0, Math.min(1, x / width)); } } } Text { id: pct anchors.verticalCenter: parent.verticalCenter width: 44 horizontalAlignment: Text.AlignRight text: !row.audio ? "—" : row.audio.muted ? "muted" : Math.round(row.audio.volume * 100) + "%" font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 2 } color: row.audio?.muted ? Theme.red : Theme.subtext } } } Text { anchors.right: parent.right text: "Sound settings ›" font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 2 } color: drawerLink.containsMouse ? Theme.accent : Theme.subtext MouseArea { id: drawerLink anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor onClicked: panel.openDrawer() } } }