This commit is contained in:
Zacharias-Brohn
2026-02-16 18:54:36 +01:00
parent b77e728313
commit ded3ab06df
12 changed files with 903 additions and 46 deletions
+61
View File
@@ -0,0 +1,61 @@
import QtQuick
import QtQuick.Shapes
import qs.Components
import qs.Helpers
import qs.Config
import qs.Modules as Modules
ShapePath {
id: root
required property Wrapper wrapper
readonly property real rounding: 8
readonly property bool flatten: wrapper.width < rounding * 2
readonly property real roundingX: flatten ? wrapper.width / 2 : rounding
strokeWidth: -1
fillColor: DynamicColors.palette.m3surface
PathArc {
relativeX: -root.roundingX
relativeY: root.rounding
radiusX: Math.min(root.rounding, root.wrapper.width)
radiusY: root.rounding
}
PathLine {
relativeX: -(root.wrapper.width - root.roundingX * 2)
relativeY: 0
}
PathArc {
relativeX: -root.roundingX
relativeY: root.rounding
radiusX: Math.min(root.rounding, root.wrapper.width)
radiusY: root.rounding
direction: PathArc.Counterclockwise
}
PathLine {
relativeX: 0
relativeY: root.wrapper.height - root.rounding * 2
}
PathArc {
relativeX: root.roundingX
relativeY: root.rounding
radiusX: Math.min(root.rounding, root.wrapper.width)
radiusY: root.rounding
direction: PathArc.Counterclockwise
}
PathLine {
relativeX: root.wrapper.width - root.roundingX * 2
relativeY: 0
}
PathArc {
relativeX: root.roundingX
relativeY: root.rounding
radiusX: Math.min(root.rounding, root.wrapper.width)
radiusY: root.rounding
}
Behavior on fillColor {
Modules.CAnim {}
}
}
+128
View File
@@ -0,0 +1,128 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Helpers
import qs.Config
import qs.Modules.Dashboard.Dash
import qs.Modules as Modules
Item {
id: root
required property Brightness.Monitor monitor
required property var visibilities
required property real volume
required property bool muted
required property real sourceVolume
required property bool sourceMuted
required property real brightness
implicitWidth: layout.implicitWidth + Appearance.padding.large * 2
implicitHeight: layout.implicitHeight + Appearance.padding.large * 2
ColumnLayout {
id: layout
anchors.centerIn: parent
spacing: Appearance.spacing.normal
// Speaker volume
CustomMouseArea {
implicitWidth: Config.osd.sizes.sliderWidth
implicitHeight: Config.osd.sizes.sliderHeight
function onWheel(event: WheelEvent) {
if (event.angleDelta.y > 0)
Audio.incrementVolume();
else if (event.angleDelta.y < 0)
Audio.decrementVolume();
}
FilledSlider {
anchors.fill: parent
icon: Icons.getVolumeIcon(value, root.muted)
value: root.volume
to: Config.services.maxVolume
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
function onWheel(event: WheelEvent) {
if (event.angleDelta.y > 0)
Audio.incrementSourceVolume();
else if (event.angleDelta.y < 0)
Audio.decrementSourceVolume();
}
FilledSlider {
anchors.fill: parent
icon: Icons.getMicVolumeIcon(value, root.sourceMuted)
value: root.sourceVolume
to: Config.services.maxVolume
color: Audio.sourceMuted ? DynamicColors.palette.m3error : DynamicColors.palette.m3secondary
onMoved: Audio.setSourceVolume(value)
}
}
}
// Brightness
WrappedLoader {
shouldBeActive: Config.osd.enableBrightness
sourceComponent: CustomMouseArea {
implicitWidth: Config.osd.sizes.sliderWidth
implicitHeight: Config.osd.sizes.sliderHeight
function onWheel(event: WheelEvent) {
const monitor = root.monitor;
if (!monitor)
return;
if (event.angleDelta.y > 0)
monitor.setBrightness(monitor.brightness + Config.services.brightnessIncrement);
else if (event.angleDelta.y < 0)
monitor.setBrightness(monitor.brightness - Config.services.brightnessIncrement);
}
FilledSlider {
anchors.fill: parent
icon: `brightness_${(Math.round(value * 6) + 1)}`
value: root.brightness
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
visible: active
Behavior on Layout.preferredHeight {
Modules.Anim {
easing.bezierCurve: Appearance.anim.curves.emphasized
}
}
Behavior on opacity {
Modules.Anim {}
}
}
}
+136
View File
@@ -0,0 +1,136 @@
pragma ComponentBehavior: Bound
import Quickshell
import QtQuick
import qs.Components
import qs.Helpers
import qs.Config
import qs.Modules as Modules
import qs.Modules.Dashboard.Dash
Item {
id: root
required property ShellScreen screen
required property var visibilities
property bool hovered
readonly property Brightness.Monitor monitor: Brightness.getMonitorForScreen(root.screen)
readonly property bool shouldBeActive: visibilities.osd && Config.osd.enabled && !(visibilities.utilities && Config.utilities.enabled)
property real volume
property bool muted
property real sourceVolume
property bool sourceMuted
property real brightness
function show(): void {
visibilities.osd = true;
timer.restart();
}
Component.onCompleted: {
volume = Audio.volume;
muted = Audio.muted;
sourceVolume = Audio.sourceVolume;
sourceMuted = Audio.sourceMuted;
brightness = root.monitor?.brightness ?? 0;
}
visible: width > 0
implicitWidth: 0
implicitHeight: content.implicitHeight
states: State {
name: "visible"
when: root.shouldBeActive
PropertyChanges {
root.implicitWidth: content.implicitWidth
}
}
transitions: [
Transition {
from: ""
to: "visible"
Modules.Anim {
target: root
property: "implicitWidth"
easing.bezierCurve: MaterialEasing.expressiveEffects
}
},
Transition {
from: "visible"
to: ""
Modules.Anim {
target: root
property: "implicitWidth"
easing.bezierCurve: MaterialEasing.expressiveEffects
}
}
]
Connections {
target: Audio
function onMutedChanged(): void {
root.show();
root.muted = Audio.muted;
}
function onVolumeChanged(): void {
root.show();
root.volume = Audio.volume;
}
function onSourceMutedChanged(): void {
root.show();
root.sourceMuted = Audio.sourceMuted;
}
function onSourceVolumeChanged(): void {
root.show();
root.sourceVolume = Audio.sourceVolume;
}
}
Connections {
target: root.monitor
function onBrightnessChanged(): void {
root.show();
root.brightness = root.monitor?.brightness ?? 0;
}
}
Timer {
id: timer
interval: Config.osd.hideDelay
onTriggered: {
if (!root.hovered)
root.visibilities.osd = false;
}
}
Loader {
id: content
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
Component.onCompleted: active = Qt.binding(() => root.shouldBeActive || root.visible)
sourceComponent: Content {
monitor: root.monitor
visibilities: root.visibilities
volume: root.volume
muted: root.muted
sourceVolume: root.sourceVolume
sourceMuted: root.sourceMuted
brightness: root.brightness
}
}
}