osd: unify brightness and volume

This commit is contained in:
end-4
2025-09-28 18:04:57 +02:00
parent 01ab0f5ab9
commit bd8e004795
7 changed files with 92 additions and 206 deletions
@@ -356,7 +356,7 @@ Singleton {
property real mediaControlsWidth: 440
property real mediaControlsHeight: 160
property real notificationPopupWidth: 410
property real osdWidth: 200
property real osdWidth: 180
property real searchWidthCollapsed: 260
property real searchWidth: 450
property real sidebarWidth: 460
@@ -15,9 +15,21 @@ Scope {
property string protectionMessage: ""
property var focusedScreen: Quickshell.screens.find(s => s.name === Hyprland.focusedMonitor?.name)
property string currentIndicator: "volume"
property var indicators: [
{
id: "volume",
sourceUrl: "indicators/VolumeIndicator.qml"
},
{
id: "brightness",
sourceUrl: "indicators/BrightnessIndicator.qml"
},
]
function triggerOsd() {
GlobalStates.osdVolumeOpen = true
osdTimeout.restart()
GlobalStates.osdVolumeOpen = true;
osdTimeout.restart();
}
Timer {
@@ -26,35 +38,44 @@ Scope {
repeat: false
running: false
onTriggered: {
GlobalStates.osdVolumeOpen = false
root.protectionMessage = ""
GlobalStates.osdVolumeOpen = false;
root.protectionMessage = "";
}
}
Connections {
target: Brightness
function onBrightnessChanged() {
GlobalStates.osdVolumeOpen = false
root.protectionMessage = "";
root.currentIndicator = "brightness";
root.triggerOsd();
}
}
Connections { // Listen to volume changes
Connections {
// Listen to volume changes
target: Audio.sink?.audio ?? null
function onVolumeChanged() {
if (!Audio.ready) return
root.triggerOsd()
if (!Audio.ready)
return;
root.currentIndicator = "volume";
root.triggerOsd();
}
function onMutedChanged() {
if (!Audio.ready) return
root.triggerOsd()
if (!Audio.ready)
return;
root.currentIndicator = "volume";
root.triggerOsd();
}
}
Connections { // Listen to protection triggers
Connections {
// Listen to protection triggers
target: Audio
function onSinkProtectionTriggered(reason) {
root.protectionMessage = reason;
root.triggerOsd()
root.currentIndicator = "volume";
root.triggerOsd();
}
}
@@ -69,7 +90,7 @@ Scope {
Connections {
target: root
function onFocusedScreenChanged() {
osdRoot.screen = root.focusedScreen
osdRoot.screen = root.focusedScreen;
}
}
@@ -97,10 +118,11 @@ Scope {
ColumnLayout {
id: columnLayout
anchors.horizontalCenter: parent.horizontalCenter
Item {
id: osdValuesWrapper
// Extra space for shadow
implicitHeight: contentColumnLayout.implicitHeight + Appearance.sizes.elevationMargin * 2
implicitHeight: contentColumnLayout.implicitHeight
implicitWidth: contentColumnLayout.implicitWidth
clip: true
@@ -110,30 +132,25 @@ Scope {
onEntered: GlobalStates.osdVolumeOpen = false
}
ColumnLayout {
Column {
id: contentColumnLayout
anchors {
top: parent.top
left: parent.left
right: parent.right
leftMargin: Appearance.sizes.elevationMargin
rightMargin: Appearance.sizes.elevationMargin
}
spacing: 0
OsdValueIndicator {
id: osdValues
Layout.fillWidth: true
value: Audio.sink?.audio.volume ?? 0
icon: Audio.sink?.audio.muted ? "volume_off" : "volume_up"
name: Translation.tr("Volume")
Loader {
id: osdIndicatorLoader
source: root.indicators.find(i => i.id === root.currentIndicator)?.sourceUrl
}
Item {
id: protectionMessageWrapper
anchors.horizontalCenter: parent.horizontalCenter
implicitHeight: protectionMessageBackground.implicitHeight
implicitWidth: protectionMessageBackground.implicitWidth
Layout.alignment: Qt.AlignHCenter
opacity: root.protectionMessage !== "" ? 1 : 0
StyledRectangularShadow {
@@ -174,26 +191,26 @@ Scope {
}
IpcHandler {
target: "osdVolume"
target: "osdVolume"
function trigger() {
root.triggerOsd()
function trigger() {
root.triggerOsd();
}
function hide() {
GlobalStates.osdVolumeOpen = false
GlobalStates.osdVolumeOpen = false;
}
function toggle() {
GlobalStates.osdVolumeOpen = !GlobalStates.osdVolumeOpen
GlobalStates.osdVolumeOpen = !GlobalStates.osdVolumeOpen;
}
}
}
GlobalShortcut {
name: "osdVolumeTrigger"
description: "Triggers volume OSD on press"
onPressed: {
root.triggerOsd()
root.triggerOsd();
}
}
GlobalShortcut {
@@ -201,8 +218,7 @@ Scope {
description: "Hides volume OSD on press"
onPressed: {
GlobalStates.osdVolumeOpen = false
GlobalStates.osdVolumeOpen = false;
}
}
}
@@ -1,157 +0,0 @@
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import Quickshell.Hyprland
import Quickshell.Wayland
Scope {
id: root
property var focusedScreen: Quickshell.screens.find(s => s.name === Hyprland.focusedMonitor?.name)
property var brightnessMonitor: Brightness.getMonitorForScreen(focusedScreen)
function triggerOsd() {
GlobalStates.osdBrightnessOpen = true
osdTimeout.restart()
}
Timer {
id: osdTimeout
interval: Config.options.osd.timeout
repeat: false
running: false
onTriggered: {
GlobalStates.osdBrightnessOpen = false
}
}
Connections {
target: Audio.sink?.audio ?? null
function onVolumeChanged() {
if (!Audio.ready) return
GlobalStates.osdBrightnessOpen = false
}
}
Connections {
target: Brightness
function onBrightnessChanged() {
if (!root.brightnessMonitor.ready) return
root.triggerOsd()
}
}
Loader {
id: osdLoader
active: GlobalStates.osdBrightnessOpen
sourceComponent: PanelWindow {
id: osdRoot
color: "transparent"
Connections {
target: root
function onFocusedScreenChanged() {
osdRoot.screen = root.focusedScreen
}
}
WlrLayershell.namespace: "quickshell:onScreenDisplay"
WlrLayershell.layer: WlrLayer.Overlay
anchors {
top: !Config.options.bar.bottom
bottom: Config.options.bar.bottom
}
mask: Region {
item: osdValuesWrapper
}
exclusionMode: ExclusionMode.Ignore
exclusiveZone: 0
margins {
top: Appearance.sizes.barHeight
bottom: Appearance.sizes.barHeight
}
implicitWidth: columnLayout.implicitWidth
implicitHeight: columnLayout.implicitHeight
visible: osdLoader.active
ColumnLayout {
id: columnLayout
anchors.horizontalCenter: parent.horizontalCenter
Item {
id: osdValuesWrapper
// Extra space for shadow
implicitHeight: osdValues.implicitHeight + Appearance.sizes.elevationMargin * 2
implicitWidth: osdValues.implicitWidth
clip: true
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: GlobalStates.osdBrightnessOpen = false
}
Behavior on implicitHeight {
NumberAnimation {
duration: Appearance.animation.menuDecel.duration
easing.type: Appearance.animation.menuDecel.type
}
}
OsdValueIndicator {
id: osdValues
anchors.fill: parent
anchors.margins: Appearance.sizes.elevationMargin
value: root.brightnessMonitor?.brightness ?? 50
icon: "light_mode"
rotateIcon: true
scaleIcon: true
name: Translation.tr("Brightness")
}
}
}
}
}
IpcHandler {
target: "osdBrightness"
function trigger() {
root.triggerOsd()
}
function hide() {
GlobalStates.osdBrightnessOpen = false
}
function toggle() {
GlobalStates.osdBrightnessOpen = !GlobalStates.osdBrightnessOpen
}
}
GlobalShortcut {
name: "osdBrightnessTrigger"
description: "Triggers brightness OSD on press"
onPressed: {
root.triggerOsd()
}
}
GlobalShortcut {
name: "osdBrightnessHide"
description: "Hides brightness OSD on press"
onPressed: {
GlobalStates.osdBrightnessOpen = false
}
}
}
@@ -1,13 +1,8 @@
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import QtQuick
import QtQuick.Controls
import QtQuick.Effects
import QtQuick.Layouts
import Quickshell
import Quickshell.Widgets
// import Qt5Compat.GraphicalEffects
Item {
id: root
@@ -21,19 +16,23 @@ Item {
property real valueIndicatorLeftPadding: 10
property real valueIndicatorRightPadding: 20 // An icon is circle ish, a column isn't, hence the extra padding
Layout.margins: Appearance.sizes.elevationMargin
implicitWidth: Appearance.sizes.osdWidth
implicitHeight: valueIndicator.implicitHeight
implicitWidth: Appearance.sizes.osdWidth + 2 * Appearance.sizes.elevationMargin
implicitHeight: valueIndicator.implicitHeight + 2 * Appearance.sizes.elevationMargin
StyledRectangularShadow {
target: valueIndicator
}
WrapperRectangle {
Rectangle {
id: valueIndicator
anchors.fill: parent
anchors {
fill: parent
margins: Appearance.sizes.elevationMargin
}
radius: Appearance.rounding.full
color: Appearance.colors.colLayer0
implicitWidth: valueRow.implicitWidth
implicitHeight: valueRow.implicitHeight
RowLayout { // Icon on the left, stuff on the right
id: valueRow
@@ -48,6 +47,7 @@ Item {
Layout.leftMargin: valueIndicatorLeftPadding
Layout.topMargin: valueIndicatorVerticalPadding
Layout.bottomMargin: valueIndicatorVerticalPadding
MaterialSymbol { // Icon
anchors {
centerIn: parent
@@ -101,4 +101,4 @@ Item {
}
}
}
}
}
@@ -0,0 +1,18 @@
import qs
import qs.services
import QtQuick
import Quickshell
import Quickshell.Hyprland
import "../"
OsdValueIndicator {
id: root
property var focusedScreen: Quickshell.screens.find(s => s.name === Hyprland.focusedMonitor?.name)
property var brightnessMonitor: Brightness.getMonitorForScreen(focusedScreen)
value: root.brightnessMonitor?.brightness ?? 50
icon: "light_mode"
rotateIcon: true
scaleIcon: true
name: Translation.tr("Brightness")
}
@@ -0,0 +1,11 @@
import qs
import qs.services
import QtQuick
import "../"
OsdValueIndicator {
id: osdValues
value: Audio.sink?.audio.volume ?? 0
icon: Audio.sink?.audio.muted ? "volume_off" : "volume_up"
name: Translation.tr("Volume")
}
+2 -4
View File
@@ -42,8 +42,7 @@ ShellRoot {
property bool enableLock: true
property bool enableMediaControls: true
property bool enableNotificationPopup: true
property bool enableOnScreenDisplayBrightness: true
property bool enableOnScreenDisplayVolume: true
property bool enableOnScreenDisplay: true
property bool enableOnScreenKeyboard: true
property bool enableOverview: true
property bool enableReloadPopup: true
@@ -72,8 +71,7 @@ ShellRoot {
LazyLoader { active: enableLock; component: Lock {} }
LazyLoader { active: enableMediaControls; component: MediaControls {} }
LazyLoader { active: enableNotificationPopup; component: NotificationPopup {} }
LazyLoader { active: enableOnScreenDisplayBrightness; component: OnScreenDisplayBrightness {} }
LazyLoader { active: enableOnScreenDisplayVolume; component: OnScreenDisplayVolume {} }
LazyLoader { active: enableOnScreenDisplay; component: OnScreenDisplay {} }
LazyLoader { active: enableOnScreenKeyboard; component: OnScreenKeyboard {} }
LazyLoader { active: enableOverview; component: Overview {} }
LazyLoader { active: enableReloadPopup; component: ReloadPopup {} }