From f75ebb4b5f366274cfa2e9cabdef03dcb042c9e6 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Sat, 7 Nov 2026 11:56:01 +0100 Subject: island: the panel slider as its own file, for the Sonix panel too Co-Authored-By: Claude Sonnet 5.5 --- desktop/island/HeadphonesPanel.qml | 98 ++-------------------------------- desktop/island/PanelSlider.qml | 106 +++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 94 deletions(-) create mode 100644 desktop/island/PanelSlider.qml (limited to 'desktop') diff --git a/desktop/island/HeadphonesPanel.qml b/desktop/island/HeadphonesPanel.qml index 315bc6b..49a356e 100644 --- a/desktop/island/HeadphonesPanel.qml +++ b/desktop/island/HeadphonesPanel.qml @@ -267,7 +267,8 @@ Column { // Ambient level 1-20, while in ambient mode. Wheel or drag, sent once it // settles (levelSend above). - Slider { + PanelSlider { + width: panel.width visible: panel.mode === "ambient" cp: 0xF07C5 // md-ear_hearing value: panel.shownLevel / 20 @@ -311,7 +312,8 @@ Column { } // The headphones' volume; the icon mutes, the wheel steps 5%. - Slider { + PanelSlider { + width: panel.width enabled: panel.audio !== null icon: Logic.volumeIcon(panel.audio?.volume ?? 0, panel.audio?.muted ?? false) value: panel.audio?.volume ?? 0 @@ -408,96 +410,4 @@ Column { } } } - - // One slider row: a glyph (cp) or a named icon (icon), a track, a label. - // moved(v) gives 0..1 from a click or drag; stepped(+1|-1) one wheel notch. - component Slider: Row { - id: row - property int cp: 0 - property string icon: "" - property real value: 0 - property bool muted: false - property string label: "" - signal moved(real v) - signal stepped(int d) - signal iconClicked() - - width: panel.width - spacing: 10 - - Item { - anchors.verticalCenter: parent.verticalCenter - width: 20 - height: 20 - - Text { - visible: row.icon === "" - anchors.centerIn: parent - text: panel.glyph(row.cp) - font { family: Theme.iconFamily; pixelSize: 20 } - color: Theme.subtext - } - - IconImage { - visible: row.icon !== "" - anchors.centerIn: parent - implicitSize: 18 - source: row.icon !== "" ? Quickshell.iconPath(row.icon, true) : "" - } - - MouseArea { - anchors.fill: parent - enabled: row.enabled - cursorShape: Qt.PointingHandCursor - onClicked: row.iconClicked() - } - } - - Rectangle { - anchors.verticalCenter: parent.verticalCenter - width: row.width - 20 - 44 - row.spacing * 2 - height: 8 - radius: 4 - color: Theme.surface - - Rectangle { - height: parent.height - radius: parent.radius - width: parent.width * Math.max(0, Math.min(1, row.value)) - color: row.muted ? Theme.red : Theme.accent - opacity: row.muted ? 0.5 : 1 - } - - // Taller than the track so it is easy to hit. A MouseArea for the - // wheel, not a WheelHandler (AGENTS.md); one step per notch (120), - // since a touchpad sends many small deltas. - MouseArea { - anchors { fill: parent; topMargin: -8; bottomMargin: -8 } - enabled: row.enabled - preventStealing: true - cursorShape: Qt.PointingHandCursor - property real acc: 0 - function at(x) { return Math.max(0, Math.min(1, x / width)); } - onPressed: mouse => row.moved(at(mouse.x)) - onPositionChanged: mouse => { if (pressed) row.moved(at(mouse.x)); } - onWheel: wheel => { - acc += wheel.angleDelta.y; - while (Math.abs(acc) >= 120) { - row.stepped(acc > 0 ? 1 : -1); - acc -= acc > 0 ? 120 : -120; - } - wheel.accepted = true; - } - } - } - - Text { - anchors.verticalCenter: parent.verticalCenter - width: 44 - horizontalAlignment: Text.AlignRight - text: row.label - font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 2 } - color: row.muted ? Theme.red : Theme.subtext - } - } } diff --git a/desktop/island/PanelSlider.qml b/desktop/island/PanelSlider.qml new file mode 100644 index 0000000..bbc0872 --- /dev/null +++ b/desktop/island/PanelSlider.qml @@ -0,0 +1,106 @@ +// 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 ".." + +// An icon, a track and a label: drag or click sets, the wheel steps one per +// notch. Shared by the headphones and Sonix panels. The width is the user's. +Row { + id: row + property int cp: 0 + property string icon: "" + property real value: 0 + property bool muted: false + property string label: "" + signal moved(real v) + signal stepped(int d) + signal iconClicked() + + spacing: 10 + + Item { + anchors.verticalCenter: parent.verticalCenter + width: 20 + height: 20 + + Text { + visible: row.icon === "" + anchors.centerIn: parent + text: String.fromCodePoint(row.cp) + font { family: Theme.iconFamily; pixelSize: 20 } + color: Theme.subtext + } + + IconImage { + visible: row.icon !== "" + anchors.centerIn: parent + implicitSize: 18 + source: row.icon !== "" ? Quickshell.iconPath(row.icon, true) : "" + } + + MouseArea { + anchors.fill: parent + enabled: row.enabled + cursorShape: Qt.PointingHandCursor + onClicked: row.iconClicked() + } + } + + Rectangle { + anchors.verticalCenter: parent.verticalCenter + width: row.width - 20 - 44 - row.spacing * 2 + height: 8 + radius: 4 + color: Theme.surface + + Rectangle { + height: parent.height + radius: parent.radius + width: parent.width * Math.max(0, Math.min(1, row.value)) + color: row.muted ? Theme.red : Theme.accent + opacity: row.muted ? 0.5 : 1 + } + + // Taller than the track so it is easy to hit. A MouseArea for the + // wheel, not a WheelHandler (AGENTS.md); one step per notch (120), + // since a touchpad sends many small deltas. + MouseArea { + anchors { fill: parent; topMargin: -8; bottomMargin: -8 } + enabled: row.enabled + preventStealing: true + cursorShape: Qt.PointingHandCursor + property real acc: 0 + function at(x) { return Math.max(0, Math.min(1, x / width)); } + onPressed: mouse => row.moved(at(mouse.x)) + onPositionChanged: mouse => { if (pressed) row.moved(at(mouse.x)); } + onWheel: wheel => { + acc += wheel.angleDelta.y; + while (Math.abs(acc) >= 120) { + row.stepped(acc > 0 ? 1 : -1); + acc -= acc > 0 ? 120 : -120; + } + wheel.accepted = true; + } + } + } + + Text { + anchors.verticalCenter: parent.verticalCenter + width: 44 + horizontalAlignment: Text.AlignRight + text: row.label + font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 2 } + color: row.muted ? Theme.red : Theme.subtext + } +} -- cgit v1.2.3