import QtQuick import QtQuick.Layouts import Quickshell.Services.Pipewire import "../config" // PipeWire default sink volume. Scroll to adjust, click to mute. MouseArea { id: root readonly property var sink: Pipewire.defaultAudioSink readonly property var audio: sink ? sink.audio : null readonly property bool muted: audio ? audio.muted : true readonly property int volPct: audio ? Math.round(audio.volume * 100) : 0 implicitWidth: pill.implicitWidth implicitHeight: pill.implicitHeight cursorShape: Qt.PointingHandCursor acceptedButtons: Qt.LeftButton // accumulate raw wheel deltas so high-res / inertial scrolling doesn't // fire a full step per micro-event; one notch (120 units) == one step property real _wheelAccum: 0 readonly property real _wheelStep: 0.02 onClicked: { if (audio) audio.muted = !audio.muted; } onWheel: wheel => { if (!audio) return; _wheelAccum += wheel.angleDelta.y; const notches = Math.trunc(_wheelAccum / 120); if (notches === 0) return; _wheelAccum -= notches * 120; audio.volume = Math.max(0, Math.min(1, audio.volume + notches * _wheelStep)); } // keep the sink's audio properties live PwObjectTracker { objects: root.sink ? [root.sink] : [] } Pill { id: pill anchors.fill: parent Text { text: root.muted ? Icons.volMute : root.volPct < 50 ? Icons.volLow : Icons.volHigh font.family: Theme.monoFont font.pixelSize: Theme.fontSize + 1 color: root.muted ? Theme.overlay : Theme.teal Layout.alignment: Qt.AlignVCenter Layout.preferredWidth: Theme.fontSize + 4 horizontalAlignment: Text.AlignHCenter } TextMetrics { id: volMetrics font: volText.font text: "muted" } Text { id: volText text: root.muted ? "muted" : root.volPct + "%" font.family: Theme.font font.pixelSize: Theme.fontSize color: Theme.text horizontalAlignment: Text.AlignRight Layout.alignment: Qt.AlignVCenter Layout.preferredWidth: volMetrics.advanceWidth } } }