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
+41 -36
View File
@@ -25,7 +25,6 @@ Variants {
color: "transparent"
property var root: Quickshell.shellDir
WlrLayershell.layer: WlrLayer.Overlay
WlrLayershell.namespace: "ZShell-Bar"
WlrLayershell.exclusionMode: ExclusionMode.Ignore
@@ -96,6 +95,7 @@ Variants {
property bool sidebar
property bool dashboard
property bool bar
property bool osd
Component.onCompleted: Visibilities.load(scope.modelData, this)
}
@@ -122,44 +122,48 @@ Variants {
}
}
MouseArea {
Interactions {
id: mouseArea
screen: scope.modelData
popouts: panels.popouts
visibilities: visibilities
panels: panels
bar: barLoader
anchors.fill: parent
hoverEnabled: true
onContainsMouseChanged: {
if ( !containsMouse ) {
panels.popouts.hasCurrent = false;
if ( !visibilities.sidebar && !visibilities.dashboard )
visibilities.bar = Config.autoHide ? false : true;
}
}
onPositionChanged: event => {
if ( Config.autoHide && !visibilities.bar ? mouseY < 4 : mouseY < backgroundRect.implicitHeight ) {
visibilities.bar = true;
barLoader.checkPopout(mouseX);
}
}
onPressed: event => {
var traywithinX = mouseX >= panels.popouts.x + 8 && mouseX < panels.popouts.x + panels.popouts.implicitWidth;
var traywithinY = mouseY >= panels.popouts.y + exclusionZone.implicitHeight && mouseY < panels.popouts.y + exclusionZone.implicitHeight + panels.popouts.implicitHeight;
var sidebarwithinX = mouseX >= bar.width - panels.sidebar.width
var dashboardWithinX = mouseX <= panels.dashboard.width + panels.dashboard.x && mouseX >= panels.dashboard.x
var dashboardWithinY = mouseY <= backgroundRect.implicitHeight + panels.dashboard.implicitHeight
if ( panels.popouts.hasCurrent ) {
if ( traywithinX && traywithinY ) {
} else {
panels.popouts.hasCurrent = false;
}
} else if ( visibilities.sidebar && !sidebarwithinX ) {
visibilities.sidebar = false;
} else if ( visibilities.dashboard && ( !dashboardWithinX || !dashboardWithinY )) {
visibilities.dashboard = false;
}
}
// onContainsMouseChanged: {
// if ( !containsMouse ) {
// panels.popouts.hasCurrent = false;
// if ( !visibilities.sidebar && !visibilities.dashboard )
// visibilities.bar = Config.autoHide ? false : true;
// }
// }
//
// onPositionChanged: event => {
// if ( Config.autoHide && !visibilities.bar ? mouseY < 4 : mouseY < backgroundRect.implicitHeight ) {
// visibilities.bar = true;
// barLoader.checkPopout(mouseX);
// }
// }
//
// onPressed: event => {
// var traywithinX = mouseX >= panels.popouts.x + 8 && mouseX < panels.popouts.x + panels.popouts.implicitWidth;
// var traywithinY = mouseY >= panels.popouts.y + exclusionZone.implicitHeight && mouseY < panels.popouts.y + exclusionZone.implicitHeight + panels.popouts.implicitHeight;
// var sidebarwithinX = mouseX >= bar.width - panels.sidebar.width
// var dashboardWithinX = mouseX <= panels.dashboard.width + panels.dashboard.x && mouseX >= panels.dashboard.x
// var dashboardWithinY = mouseY <= backgroundRect.implicitHeight + panels.dashboard.implicitHeight
//
// if ( panels.popouts.hasCurrent ) {
// if ( traywithinX && traywithinY ) {
// } else {
// panels.popouts.hasCurrent = false;
// }
// } else if ( visibilities.sidebar && !sidebarwithinX ) {
// visibilities.sidebar = false;
// } else if ( visibilities.dashboard && ( !dashboardWithinX || !dashboardWithinY )) {
// visibilities.dashboard = false;
// }
// }
Panels {
id: panels
@@ -179,6 +183,7 @@ Variants {
color: "transparent"
radius: 0
Behavior on color {
CAnim {}
}
+146
View File
@@ -0,0 +1,146 @@
import QtQuick
import QtQuick.Templates
import qs.Helpers
import qs.Config
import qs.Modules
Slider {
id: root
required property string icon
property real oldValue
property bool initialized
property color color: DynamicColors.palette.m3secondary
orientation: Qt.Vertical
background: CustomRect {
color: DynamicColors.layer(DynamicColors.palette.m3surfaceContainer, 2)
radius: Appearance.rounding.full
CustomRect {
anchors.left: parent.left
anchors.right: parent.right
y: root.handle.y
implicitHeight: parent.height - y
color: root.color
radius: parent.radius
}
}
handle: Item {
id: handle
property alias moving: icon.moving
y: root.visualPosition * (root.availableHeight - height)
implicitWidth: root.width
implicitHeight: root.width
Elevation {
anchors.fill: parent
radius: rect.radius
level: handleInteraction.containsMouse ? 2 : 1
}
CustomRect {
id: rect
anchors.fill: parent
color: DynamicColors.palette.m3inverseSurface
radius: Appearance.rounding.full
MouseArea {
id: handleInteraction
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.NoButton
}
MaterialIcon {
id: icon
property bool moving
function update(): void {
animate = !moving;
binding.when = moving;
font.pointSize = moving ? Appearance.font.size.small : Appearance.font.size.larger;
font.family = moving ? Appearance.font.family.sans : Appearance.font.family.material;
}
text: root.icon
color: DynamicColors.palette.m3inverseOnSurface
anchors.centerIn: parent
onMovingChanged: anim.restart()
Binding {
id: binding
target: icon
property: "text"
value: Math.round(root.value * 100)
when: false
}
SequentialAnimation {
id: anim
Anim {
target: icon
property: "scale"
to: 0
duration: Appearance.anim.durations.normal / 2
easing.bezierCurve: Appearance.anim.curves.standardAccel
}
ScriptAction {
script: icon.update()
}
Anim {
target: icon
property: "scale"
to: 1
duration: Appearance.anim.durations.normal / 2
easing.bezierCurve: Appearance.anim.curves.standardDecel
}
}
}
}
}
onPressedChanged: handle.moving = pressed
onValueChanged: {
if (!initialized) {
initialized = true;
return;
}
if (Math.abs(value - oldValue) < 0.01)
return;
oldValue = value;
handle.moving = true;
stateChangeDelay.restart();
}
Timer {
id: stateChangeDelay
interval: 500
onTriggered: {
if (!root.pressed)
handle.moving = false;
}
}
Behavior on value {
Anim {
duration: Appearance.anim.durations.large
}
}
}
+4
View File
@@ -33,6 +33,8 @@ Singleton {
property alias dashboard: adapter.dashboard
property alias appearance: adapter.appearance
property alias autoHide: adapter.autoHide
property alias macchiato: adapter.macchiato
property alias osd: adapter.osd
FileView {
id: root
@@ -74,6 +76,8 @@ Singleton {
property DashboardConfig dashboard: DashboardConfig {}
property AppearanceConf appearance: AppearanceConf {}
property bool autoHide: false
property bool macchiato: false
property Osd osd: Osd {}
}
}
}
+61
View File
@@ -214,4 +214,65 @@ Singleton {
property color m3onTertiaryFixed: "#2f1500"
property color m3onTertiaryFixedVariant: "#623f21"
}
component M3MaccchiatoPalette: QtObject {
property color m3primary_paletteKeyColor: "#6a73ac"
property color m3secondary_paletteKeyColor: "#72758e"
property color m3tertiary_paletteKeyColor: "#9b6592"
property color m3neutral_paletteKeyColor: "#77767b"
property color m3neutral_variant_paletteKeyColor: "#767680"
property color m3background: "#131317"
property color m3onBackground: "#e4e1e7"
property color m3surface: "#131317"
property color m3surfaceDim: "#131317"
property color m3surfaceBright: "#39393d"
property color m3surfaceContainerLowest: "#0e0e12"
property color m3surfaceContainerLow: "#1b1b1f"
property color m3surfaceContainer: "#1f1f23"
property color m3surfaceContainerHigh: "#2a2a2e"
property color m3surfaceContainerHighest: "#353438"
property color m3onSurface: "#e4e1e7"
property color m3surfaceVariant: "#46464f"
property color m3onSurfaceVariant: "#c6c5d1"
property color m3inverseSurface: "#e4e1e7"
property color m3inverseOnSurface: "#303034"
property color m3outline: "#90909a"
property color m3outlineVariant: "#46464f"
property color m3shadow: "#000000"
property color m3scrim: "#000000"
property color m3surfaceTint: "#bac3ff"
property color m3primary: "#bac3ff"
property color m3onPrimary: "#232c60"
property color m3primaryContainer: "#6a73ac"
property color m3onPrimaryContainer: "#ffffff"
property color m3inversePrimary: "#525b92"
property color m3secondary: "#c3c5e0"
property color m3onSecondary: "#2c2f44"
property color m3secondaryContainer: "#42455c"
property color m3onSecondaryContainer: "#b1b3ce"
property color m3tertiary: "#f1b3e5"
property color m3onTertiary: "#4c1f48"
property color m3tertiaryContainer: "#b77ead"
property color m3onTertiaryContainer: "#000000"
property color m3error: "#ffb4ab"
property color m3onError: "#690005"
property color m3errorContainer: "#93000a"
property color m3onErrorContainer: "#ffdad6"
property color m3primaryFixed: "#dee0ff"
property color m3primaryFixedDim: "#bac3ff"
property color m3onPrimaryFixed: "#0b154b"
property color m3onPrimaryFixedVariant: "#3a4378"
property color m3secondaryFixed: "#dfe1fd"
property color m3secondaryFixedDim: "#c3c5e0"
property color m3onSecondaryFixed: "#171a2e"
property color m3onSecondaryFixedVariant: "#42455c"
property color m3tertiaryFixed: "#ffd7f4"
property color m3tertiaryFixedDim: "#f1b3e5"
property color m3onTertiaryFixed: "#340831"
property color m3onTertiaryFixedVariant: "#66365f"
property color m3success: "#B5CCBA"
property color m3onSuccess: "#213528"
property color m3successContainer: "#374B3E"
property color m3onSuccessContainer: "#D1E9D6"
}
}
+14
View File
@@ -0,0 +1,14 @@
import Quickshell.Io
JsonObject {
property bool enabled: true
property int hideDelay: 5000
property bool enableBrightness: true
property bool enableMicrophone: true
property Sizes sizes: Sizes {}
component Sizes: JsonObject {
property int sliderWidth: 30
property int sliderHeight: 150
}
}
+5
View File
@@ -3,7 +3,12 @@ import QtQuick
JsonObject {
property string weatherLocation: ""
property bool useFahrenheit: [Locale.ImperialUSSystem, Locale.ImperialSystem].includes(Qt.locale().measurementSystem)
property bool useTwelveHourClock: Qt.locale().timeFormat(Locale.ShortFormat).toLowerCase().includes("a")
property string gpuType: ""
property real audioIncrement: 0.1
property real brightnessIncrement: 0.1
property real maxVolume: 1.0
property string defaultPlayer: "Spotify"
property list<var> playerAliases: [
{
+11 -1
View File
@@ -6,6 +6,7 @@ import qs.Modules.Notifications as Notifications
import qs.Modules.Notifications.Sidebar as Sidebar
import qs.Modules.Notifications.Sidebar.Utils as Utils
import qs.Modules.Dashboard as Dashboard
import qs.Modules.Osd as Osd
Shape {
id: root
@@ -16,9 +17,18 @@ Shape {
anchors.fill: parent
// anchors.margins: 8
anchors.topMargin: !root.visibilities.bar ? 4 : bar.implicitHeight
anchors.topMargin: bar.implicitHeight
preferredRendererType: Shape.CurveRenderer
Component.onCompleted: console.log(root.bar.implicitHeight, root.bar.anchors.topMargin)
Osd.Background {
wrapper: root.panels.osd
startX: root.width - root.panels.sidebar.width
startY: ( root.height - wrapper.height ) / 2 - rounding
}
Modules.Background {
wrapper: root.panels.popouts
invertBottomRounding: wrapper.x <= 0
+273
View File
@@ -0,0 +1,273 @@
import Quickshell
import QtQuick
import qs.Components
import qs.Config
import qs.Modules as BarPopouts
CustomMouseArea {
id: root
required property ShellScreen screen
required property BarPopouts.Wrapper popouts
required property PersistentProperties visibilities
required property Panels panels
required property Item bar
property point dragStart
property bool dashboardShortcutActive
property bool osdShortcutActive
property bool utilitiesShortcutActive
function withinPanelHeight(panel: Item, x: real, y: real): bool {
const panelY = panel.y + bar.implicitHeight;
return y >= panelY && y <= panelY + panel.height;
}
function withinPanelWidth(panel: Item, x: real, y: real): bool {
const panelX = panel.x;
return x >= panelX && x <= panelX + panel.width;
}
function inLeftPanel(panel: Item, x: real, y: real): bool {
return x < panel.x + panel.width && withinPanelHeight(panel, x, y);
}
function inRightPanel(panel: Item, x: real, y: real): bool {
return x > panel.x && withinPanelHeight(panel, x, y);
}
function inTopPanel(panel: Item, x: real, y: real): bool {
return y < bar.implicitHeight + panel.height && withinPanelWidth(panel, x, y);
}
function inBottomPanel(panel: Item, x: real, y: real): bool {
return y > root.height - panel.height && withinPanelWidth(panel, x, y);
}
function onWheel(event: WheelEvent): void {
if (event.x < bar.implicitWidth) {
bar.handleWheel(event.y, event.angleDelta);
}
}
anchors.fill: parent
hoverEnabled: true
onPressed: event => {
if ( root.popouts.hasCurrent && !inTopPanel( root.popouts, event.x, event.y )) {
root.popouts.hasCurrent = false;
} else if (root.visibilities.sidebar && !inRightPanel( panels.sidebar, event.x, event.y )) {
root.visibilities.sidebar = false;
} else if (root.visibilities.dashboard && !inTopPanel( panels.dashboard, event.x, event.y )) {
root.visibilities.dashboard = false;
}
}
onContainsMouseChanged: {
if (!containsMouse) {
// Only hide if not activated by shortcut
if (!osdShortcutActive) {
visibilities.osd = false;
root.panels.osd.hovered = false;
}
if (!dashboardShortcutActive)
visibilities.dashboard = false;
// if (!utilitiesShortcutActive)
// visibilities.utilities = false;
if (!popouts.currentName.startsWith("traymenu") || (popouts.current?.depth ?? 0) <= 1) {
popouts.hasCurrent = false;
// bar.closeTray();
}
if (Config.autoHide)
root.visibilities.bar = false;
}
}
onPositionChanged: event => {
if (popouts.isDetached)
return;
const x = event.x;
const y = event.y;
const dragX = x - dragStart.x;
const dragY = y - dragStart.y;
// Show bar in non-exclusive mode on hover
if (!visibilities.bar && Config.autoHide && y < bar.implicitHeight + bar.anchors.topMargin)
visibilities.bar = true;
if (panels.sidebar.width === 0) {
// Show osd on hover
const showOsd = inRightPanel(panels.osd, x, y);
// // Always update visibility based on hover if not in shortcut mode
if (!osdShortcutActive) {
visibilities.osd = showOsd;
root.panels.osd.hovered = showOsd;
} else if (showOsd) {
// If hovering over OSD area while in shortcut mode, transition to hover control
osdShortcutActive = false;
root.panels.osd.hovered = true;
}
// const showSidebar = pressed && dragStart.x > bar.implicitWidth + panels.sidebar.x;
//
// // Show/hide session on drag
// if (pressed && inRightPanel(panels.session, dragStart.x, dragStart.y) && withinPanelHeight(panels.session, x, y)) {
// if (dragX < -Config.session.dragThreshold)
// visibilities.session = true;
// else if (dragX > Config.session.dragThreshold)
// visibilities.session = false;
//
// // Show sidebar on drag if in session area and session is nearly fully visible
// if (showSidebar && panels.session.width >= panels.session.nonAnimWidth && dragX < -Config.sidebar.dragThreshold)
// visibilities.sidebar = true;
// } else if (showSidebar && dragX < -Config.sidebar.dragThreshold) {
// // Show sidebar on drag if not in session area
// visibilities.sidebar = true;
// }
} else {
const outOfSidebar = x < width - panels.sidebar.width;
// Show osd on hover
const showOsd = outOfSidebar && inRightPanel(panels.osd, x, y);
// Always update visibility based on hover if not in shortcut mode
if (!osdShortcutActive) {
visibilities.osd = showOsd;
root.panels.osd.hovered = showOsd;
} else if (showOsd) {
// If hovering over OSD area while in shortcut mode, transition to hover control
osdShortcutActive = false;
root.panels.osd.hovered = true;
}
//
// // Show/hide session on drag
// if (pressed && outOfSidebar && inRightPanel(panels.session, dragStart.x, dragStart.y) && withinPanelHeight(panels.session, x, y)) {
// if (dragX < -Config.session.dragThreshold)
// visibilities.session = true;
// else if (dragX > Config.session.dragThreshold)
// visibilities.session = false;
// }
//
// // Hide sidebar on drag
// if (pressed && inRightPanel(panels.sidebar, dragStart.x, 0) && dragX > Config.sidebar.dragThreshold)
// visibilities.sidebar = false;
}
// Show launcher on hover, or show/hide on drag if hover is disabled
// if (Config.launcher.showOnHover) {
// if (!visibilities.launcher && inBottomPanel(panels.launcher, x, y))
// visibilities.launcher = true;
// } else if (pressed && inBottomPanel(panels.launcher, dragStart.x, dragStart.y) && withinPanelWidth(panels.launcher, x, y)) {
// if (dragY < -Config.launcher.dragThreshold)
// visibilities.launcher = true;
// else if (dragY > Config.launcher.dragThreshold)
// visibilities.launcher = false;
// }
//
// // Show dashboard on hover
// const showDashboard = Config.dashboard.showOnHover && inTopPanel(panels.dashboard, x, y);
//
// // Always update visibility based on hover if not in shortcut mode
// if (!dashboardShortcutActive) {
// visibilities.dashboard = showDashboard;
// } else if (showDashboard) {
// // If hovering over dashboard area while in shortcut mode, transition to hover control
// dashboardShortcutActive = false;
// }
//
// // Show/hide dashboard on drag (for touchscreen devices)
// if (pressed && inTopPanel(panels.dashboard, dragStart.x, dragStart.y) && withinPanelWidth(panels.dashboard, x, y)) {
// if (dragY > Config.dashboard.dragThreshold)
// visibilities.dashboard = true;
// else if (dragY < -Config.dashboard.dragThreshold)
// visibilities.dashboard = false;
// }
//
// // Show utilities on hover
// const showUtilities = inBottomPanel(panels.utilities, x, y);
//
// // Always update visibility based on hover if not in shortcut mode
// if (!utilitiesShortcutActive) {
// visibilities.utilities = showUtilities;
// } else if (showUtilities) {
// // If hovering over utilities area while in shortcut mode, transition to hover control
// utilitiesShortcutActive = false;
// }
// Show popouts on hover
console.log(y)
if (y < bar.implicitHeight) {
bar.checkPopout(x);
}
}
// Monitor individual visibility changes
Connections {
target: root.visibilities
function onLauncherChanged() {
// If launcher is hidden, clear shortcut flags for dashboard and OSD
if (!root.visibilities.launcher) {
root.dashboardShortcutActive = false;
root.osdShortcutActive = false;
root.utilitiesShortcutActive = false;
// Also hide dashboard and OSD if they're not being hovered
const inDashboardArea = root.inTopPanel(root.panels.dashboard, root.mouseX, root.mouseY);
const inOsdArea = root.inRightPanel(root.panels.osd, root.mouseX, root.mouseY);
if (!inDashboardArea) {
root.visibilities.dashboard = false;
}
if (!inOsdArea) {
root.visibilities.osd = false;
root.panels.osd.hovered = false;
}
}
}
function onDashboardChanged() {
if (root.visibilities.dashboard) {
// Dashboard became visible, immediately check if this should be shortcut mode
const inDashboardArea = root.inTopPanel(root.panels.dashboard, root.mouseX, root.mouseY);
if (!inDashboardArea) {
root.dashboardShortcutActive = true;
}
} else {
// Dashboard hidden, clear shortcut flag
root.dashboardShortcutActive = false;
}
}
function onOsdChanged() {
if (root.visibilities.osd) {
// OSD became visible, immediately check if this should be shortcut mode
const inOsdArea = root.inRightPanel(root.panels.osd, root.mouseX, root.mouseY);
if (!inOsdArea) {
root.osdShortcutActive = true;
}
} else {
// OSD hidden, clear shortcut flag
root.osdShortcutActive = false;
}
}
function onUtilitiesChanged() {
if (root.visibilities.utilities) {
// Utilities became visible, immediately check if this should be shortcut mode
const inUtilitiesArea = root.inBottomPanel(root.panels.utilities, root.mouseX, root.mouseY);
if (!inUtilitiesArea) {
root.utilitiesShortcutActive = true;
}
} else {
// Utilities hidden, clear shortcut flag
root.utilitiesShortcutActive = false;
}
}
}
}
+14
View File
@@ -6,6 +6,7 @@ import qs.Modules.Notifications as Notifications
import qs.Modules.Notifications.Sidebar as Sidebar
import qs.Modules.Notifications.Sidebar.Utils as Utils
import qs.Modules.Dashboard as Dashboard
import qs.Modules.Osd as Osd
import qs.Config
Item {
@@ -20,11 +21,24 @@ Item {
readonly property alias notifications: notifications
readonly property alias utilities: utilities
readonly property alias dashboard: dashboard
readonly property alias osd: osd
anchors.fill: parent
// anchors.margins: 8
anchors.topMargin: bar.implicitHeight
Osd.Wrapper {
id: osd
clip: session.width > 0 || sidebar.width > 0
screen: root.screen
visibilities: root.visibilities
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: sidebar.width
}
Modules.Wrapper {
id: popouts
+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
}
}
}