summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md1
-rw-r--r--config/OsdConfig.qml1
-rw-r--r--modules/drawers/Panels.qml2
-rw-r--r--modules/osd/Content.qml122
-rw-r--r--modules/osd/Wrapper.qml5
-rw-r--r--services/Audio.qml18
-rw-r--r--utils/Icons.qml6
7 files changed, 116 insertions, 39 deletions
diff --git a/README.md b/README.md
index 536680f..d5d1f83 100644
--- a/README.md
+++ b/README.md
@@ -326,6 +326,7 @@ default, you must create it manually.
"osd": {
"enabled": true,
"enableBrightness": true,
+ "enableMicrophone": false,
"hideDelay": 2000
},
"paths": {
diff --git a/config/OsdConfig.qml b/config/OsdConfig.qml
index ea2375b..543fc41 100644
--- a/config/OsdConfig.qml
+++ b/config/OsdConfig.qml
@@ -4,6 +4,7 @@ JsonObject {
property bool enabled: true
property int hideDelay: 2000
property bool enableBrightness: true
+ property bool enableMicrophone: false
property Sizes sizes: Sizes {}
component Sizes: JsonObject {
diff --git a/modules/drawers/Panels.qml b/modules/drawers/Panels.qml
index 0e592df..5d42d34 100644
--- a/modules/drawers/Panels.qml
+++ b/modules/drawers/Panels.qml
@@ -33,7 +33,7 @@ Item {
clip: root.visibilities.session
screen: root.screen
- visibility: root.visibilities.osd
+ visibilities: root.visibilities
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
diff --git a/modules/osd/Content.qml b/modules/osd/Content.qml
index 80fc714..707695d 100644
--- a/modules/osd/Content.qml
+++ b/modules/osd/Content.qml
@@ -1,73 +1,123 @@
pragma ComponentBehavior: Bound
+import qs.components
import qs.components.controls
import qs.services
import qs.config
import qs.utils
import QtQuick
+import QtQuick.Layouts
-Column {
+Item {
id: root
required property Brightness.Monitor monitor
-
- padding: Appearance.padding.large
+ required property var visibilities
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
- spacing: Appearance.spacing.normal
-
- // Speaker volume
- CustomMouseArea {
- implicitWidth: Config.osd.sizes.sliderWidth
- implicitHeight: Config.osd.sizes.sliderHeight
-
- onWheel: event => {
- if (event.angleDelta.y > 0)
- Audio.incrementVolume();
- else if (event.angleDelta.y < 0)
- Audio.decrementVolume();
- }
+ implicitWidth: layout.implicitWidth + Appearance.padding.large * 2
+ implicitHeight: layout.implicitHeight + Appearance.padding.large * 2
- FilledSlider {
- anchors.fill: parent
-
- icon: Icons.getVolumeIcon(value, Audio.muted)
- value: Audio.volume
- onMoved: Audio.setVolume(value)
- }
- }
+ ColumnLayout {
+ id: layout
- // Brightness
- WrappedLoader {
- active: Config.osd.enableBrightness
+ anchors.centerIn: parent
+ spacing: Appearance.spacing.normal
- sourceComponent: CustomMouseArea {
+ // Speaker volume
+ CustomMouseArea {
implicitWidth: Config.osd.sizes.sliderWidth
implicitHeight: Config.osd.sizes.sliderHeight
onWheel: event => {
- const monitor = root.monitor;
- if (!monitor)
- return;
if (event.angleDelta.y > 0)
- monitor.setBrightness(monitor.brightness + 0.1);
+ Audio.incrementVolume();
else if (event.angleDelta.y < 0)
- monitor.setBrightness(monitor.brightness - 0.1);
+ Audio.decrementVolume();
}
FilledSlider {
anchors.fill: parent
- icon: `brightness_${(Math.round(value * 6) + 1)}`
- value: root.monitor?.brightness ?? 0
- onMoved: root.monitor?.setBrightness(value)
+ icon: Icons.getVolumeIcon(value, Audio.muted)
+ value: Audio.volume
+ onMoved: Audio.setVolume(value)
+ }
+ }
+
+ // Microphone volume
+ WrappedLoader {
+ shouldBeActive: Config.osd.enableMicrophone && (!Config.osd.enableBrightness || !root.visibilities.session)
+
+ sourceComponent: CustomMouseArea {
+ implicitWidth: Config.osd.sizes.sliderWidth
+ implicitHeight: Config.osd.sizes.sliderHeight
+
+ onWheel: event => {
+ if (event.angleDelta.y > 0)
+ Audio.incrementSourceVolume();
+ else if (event.angleDelta.y < 0)
+ Audio.decrementSourceVolume();
+ }
+
+ FilledSlider {
+ anchors.fill: parent
+
+ icon: Icons.getMicVolumeIcon(value, Audio.sourceMuted)
+ value: Audio.sourceVolume
+ onMoved: Audio.setSourceVolume(value)
+ }
+ }
+ }
+
+ // Brightness
+ WrappedLoader {
+ shouldBeActive: Config.osd.enableBrightness
+
+ sourceComponent: CustomMouseArea {
+ implicitWidth: Config.osd.sizes.sliderWidth
+ implicitHeight: Config.osd.sizes.sliderHeight
+
+ onWheel: event => {
+ const monitor = root.monitor;
+ if (!monitor)
+ return;
+ if (event.angleDelta.y > 0)
+ monitor.setBrightness(monitor.brightness + 0.1);
+ else if (event.angleDelta.y < 0)
+ monitor.setBrightness(monitor.brightness - 0.1);
+ }
+
+ FilledSlider {
+ anchors.fill: parent
+
+ icon: `brightness_${(Math.round(value * 6) + 1)}`
+ value: root.monitor?.brightness ?? 0
+ onMoved: root.monitor?.setBrightness(value)
+ }
}
}
}
+
component WrappedLoader: Loader {
+ required property bool shouldBeActive
+
+ Layout.preferredHeight: shouldBeActive ? Config.osd.sizes.sliderHeight : 0
+ opacity: shouldBeActive ? 1 : 0
+ active: opacity > 0
asynchronous: true
visible: active
+
+ Behavior on Layout.preferredHeight {
+ Anim {
+ easing.bezierCurve: Appearance.anim.curves.emphasized
+ }
+ }
+
+ Behavior on opacity {
+ Anim {}
+ }
}
}
diff --git a/modules/osd/Wrapper.qml b/modules/osd/Wrapper.qml
index c1e96d6..62d8c4f 100644
--- a/modules/osd/Wrapper.qml
+++ b/modules/osd/Wrapper.qml
@@ -8,7 +8,7 @@ Item {
id: root
required property ShellScreen screen
- required property bool visibility
+ required property var visibilities
visible: width > 0
implicitWidth: 0
@@ -16,7 +16,7 @@ Item {
states: State {
name: "visible"
- when: root.visibility && Config.osd.enabled
+ when: root.visibilities.osd && Config.osd.enabled
PropertyChanges {
root.implicitWidth: content.implicitWidth
@@ -50,5 +50,6 @@ Item {
id: content
monitor: Brightness.getMonitorForScreen(root.screen)
+ visibilities: root.visibilities
}
}
diff --git a/services/Audio.qml b/services/Audio.qml
index e156e6e..a0475d0 100644
--- a/services/Audio.qml
+++ b/services/Audio.qml
@@ -29,6 +29,9 @@ Singleton {
readonly property bool muted: !!sink?.audio?.muted
readonly property real volume: sink?.audio?.volume ?? 0
+ readonly property bool sourceMuted: !!source?.audio?.muted
+ readonly property real sourceVolume: source?.audio?.volume ?? 0
+
function setVolume(newVolume: real): void {
if (sink?.ready && sink?.audio) {
sink.audio.muted = false;
@@ -44,6 +47,21 @@ Singleton {
setVolume(volume - (amount || Config.services.audioIncrement));
}
+ function setSourceVolume(newVolume: real): void {
+ if (source?.ready && source?.audio) {
+ source.audio.muted = false;
+ source.audio.volume = Math.max(0, Math.min(1, newVolume));
+ }
+ }
+
+ function incrementSourceVolume(amount: real): void {
+ setSourceVolume(sourceVolume + (amount || Config.services.audioIncrement));
+ }
+
+ function decrementSourceVolume(amount: real): void {
+ setSourceVolume(sourceVolume - (amount || Config.services.audioIncrement));
+ }
+
function setAudioSink(newSink: PwNode): void {
Pipewire.preferredDefaultAudioSink = newSink;
}
diff --git a/utils/Icons.qml b/utils/Icons.qml
index cf81d67..826ccbe 100644
--- a/utils/Icons.qml
+++ b/utils/Icons.qml
@@ -184,6 +184,12 @@ Singleton {
return "volume_mute";
}
+ function getMicVolumeIcon(volume: real, isMuted: bool): string {
+ if (!isMuted && volume > 0)
+ return "mic";
+ return "mic_off";
+ }
+
function getSpecialWsIcon(name: string): string {
name = name.toLowerCase().slice("special:".length);
if (name === "special")