summaryrefslogtreecommitdiff
path: root/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankOSD.qml
diff options
context:
space:
mode:
Diffstat (limited to 'raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankOSD.qml')
-rw-r--r--raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankOSD.qml334
1 files changed, 334 insertions, 0 deletions
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankOSD.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankOSD.qml
new file mode 100644
index 0000000..0eb0e5a
--- /dev/null
+++ b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Widgets/DankOSD.qml
@@ -0,0 +1,334 @@
+import QtQuick
+import Quickshell
+import Quickshell.Wayland
+import qs.Common
+import qs.Services
+
+PanelWindow {
+ id: root
+
+ property string blurNamespace: "dms:osd"
+ WlrLayershell.namespace: blurNamespace
+
+ property alias content: contentLoader.sourceComponent
+ property alias contentLoader: contentLoader
+ property var modelData
+ property bool shouldBeVisible: false
+ property int autoHideInterval: 2000
+ property bool enableMouseInteraction: false
+ property real osdWidth: Theme.iconSize + Theme.spacingS * 2
+ property real osdHeight: Theme.iconSize + Theme.spacingS * 2
+ property int animationDuration: Theme.mediumDuration
+ property var animationEasing: Theme.emphasizedEasing
+
+ signal osdShown
+ signal osdHidden
+
+ function show() {
+ if (SessionData.suppressOSD)
+ return;
+ if (shouldBeVisible) {
+ hideTimer.restart();
+ return;
+ }
+ OSDManager.showOSD(root);
+ closeTimer.stop();
+ shouldBeVisible = true;
+ visible = true;
+ hideTimer.restart();
+ osdShown();
+ }
+
+ function hide() {
+ shouldBeVisible = false;
+ closeTimer.restart();
+ }
+
+ function resetHideTimer() {
+ if (shouldBeVisible) {
+ hideTimer.restart();
+ }
+ }
+
+ function updateHoverState() {
+ let isHovered = (enableMouseInteraction && mouseArea.containsMouse) || osdContainer.childHovered;
+ if (enableMouseInteraction) {
+ if (isHovered) {
+ hideTimer.stop();
+ } else if (shouldBeVisible) {
+ hideTimer.restart();
+ }
+ }
+ }
+
+ function setChildHovered(hovered) {
+ osdContainer.childHovered = hovered;
+ updateHoverState();
+ }
+
+ screen: modelData
+ visible: false
+
+ Connections {
+ target: Quickshell
+ function onScreensChanged() {
+ if (!root.visible && !root.shouldBeVisible)
+ return;
+ const currentScreenName = root.screen?.name;
+ if (!currentScreenName) {
+ root.hide();
+ return;
+ }
+ for (let i = 0; i < Quickshell.screens.length; i++) {
+ if (Quickshell.screens[i].name === currentScreenName)
+ return;
+ }
+ root.shouldBeVisible = false;
+ root.visible = false;
+ hideTimer.stop();
+ closeTimer.stop();
+ osdHidden();
+ }
+ }
+
+ WlrLayershell.layer: {
+ switch (Quickshell.env("DMS_OSD_LAYER")) {
+ case "bottom":
+ console.warn("DankOSD: 'bottom' layer is not valid for OSDs. Defaulting to 'overlay' layer.");
+ return WlrLayershell.Overlay;
+ case "background":
+ console.warn("DankOSD: 'background' layer is not valid for OSDs. Defaulting to 'overlay' layer.");
+ return WlrLayershell.Overlay;
+ case "top":
+ return WlrLayershell.Top;
+ default:
+ return WlrLayershell.Overlay;
+ }
+ }
+ WlrLayershell.exclusiveZone: -1
+ WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
+
+ WindowBlur {
+ targetWindow: root
+ blurX: shadowBuffer
+ blurY: shadowBuffer
+ blurWidth: shouldBeVisible ? alignedWidth : 0
+ blurHeight: shouldBeVisible ? alignedHeight : 0
+ blurRadius: Theme.cornerRadius
+ }
+
+ color: "transparent"
+
+ readonly property real dpr: CompositorService.getScreenScale(screen)
+ readonly property real screenWidth: screen.width
+ readonly property real screenHeight: screen.height
+ readonly property real shadowBuffer: 15
+ readonly property real alignedWidth: Theme.px(osdWidth, dpr)
+ readonly property real alignedHeight: Theme.px(osdHeight, dpr)
+
+ readonly property bool isVerticalLayout: SettingsData.osdPosition === SettingsData.Position.LeftCenter || SettingsData.osdPosition === SettingsData.Position.RightCenter
+
+ readonly property real barThickness: {
+ const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default");
+ if (!defaultBar || !(defaultBar.visible ?? true))
+ return 0;
+ const innerPadding = defaultBar.innerPadding ?? 4;
+ const widgetThickness = Math.max(20, 26 + innerPadding * 0.6);
+ return Math.max(widgetThickness + innerPadding + 4, Theme.barHeight - 4 - (8 - innerPadding));
+ }
+
+ readonly property real barOffset: {
+ const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default");
+ if (!defaultBar || !(defaultBar.visible ?? true))
+ return 0;
+ const spacing = defaultBar.spacing ?? 4;
+ const bottomGap = defaultBar.bottomGap ?? 0;
+ return barThickness + spacing + bottomGap;
+ }
+
+ readonly property real dockThickness: {
+ if (!SettingsData.showDock)
+ return 0;
+ return SettingsData.dockIconSize + SettingsData.dockSpacing * 2 + 10;
+ }
+
+ readonly property real dockOffset: {
+ if (!SettingsData.showDock || SettingsData.dockAutoHide || SettingsData.dockSmartAutoHide)
+ return 0;
+ return dockThickness + SettingsData.dockSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin;
+ }
+
+ readonly property real alignedX: {
+ const margin = Theme.spacingM;
+ const centerX = (screenWidth - alignedWidth) / 2;
+
+ const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default");
+ const barPos = defaultBar?.position ?? SettingsData.Position.Top;
+
+ switch (SettingsData.osdPosition) {
+ case SettingsData.Position.Left:
+ case SettingsData.Position.Bottom:
+ const leftBarOffset = barPos === SettingsData.Position.Left ? barOffset : 0;
+ const leftDockOffset = SettingsData.dockPosition === SettingsData.Position.Left ? dockOffset : 0;
+ return Theme.snap(margin + Math.max(leftBarOffset, leftDockOffset), dpr);
+ case SettingsData.Position.Top:
+ case SettingsData.Position.Right:
+ const rightBarOffset = barPos === SettingsData.Position.Right ? barOffset : 0;
+ const rightDockOffset = SettingsData.dockPosition === SettingsData.Position.Right ? dockOffset : 0;
+ return Theme.snap(screenWidth - alignedWidth - margin - Math.max(rightBarOffset, rightDockOffset), dpr);
+ case SettingsData.Position.LeftCenter:
+ const leftCenterBarOffset = barPos === SettingsData.Position.Left ? barOffset : 0;
+ const leftCenterDockOffset = SettingsData.dockPosition === SettingsData.Position.Left ? dockOffset : 0;
+ return Theme.snap(margin + Math.max(leftCenterBarOffset, leftCenterDockOffset), dpr);
+ case SettingsData.Position.RightCenter:
+ const rightCenterBarOffset = barPos === SettingsData.Position.Right ? barOffset : 0;
+ const rightCenterDockOffset = SettingsData.dockPosition === SettingsData.Position.Right ? dockOffset : 0;
+ return Theme.snap(screenWidth - alignedWidth - margin - Math.max(rightCenterBarOffset, rightCenterDockOffset), dpr);
+ case SettingsData.Position.TopCenter:
+ case SettingsData.Position.BottomCenter:
+ default:
+ return Theme.snap(centerX, dpr);
+ }
+ }
+
+ readonly property real alignedY: {
+ const margin = Theme.spacingM;
+ const centerY = (screenHeight - alignedHeight) / 2;
+
+ const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default");
+ const barPos = defaultBar?.position ?? SettingsData.Position.Top;
+
+ switch (SettingsData.osdPosition) {
+ case SettingsData.Position.Top:
+ case SettingsData.Position.Left:
+ case SettingsData.Position.TopCenter:
+ const topBarOffset = barPos === SettingsData.Position.Top ? barOffset : 0;
+ const topDockOffset = SettingsData.dockPosition === SettingsData.Position.Top ? dockOffset : 0;
+ return Theme.snap(margin + Math.max(topBarOffset, topDockOffset), dpr);
+ case SettingsData.Position.Right:
+ case SettingsData.Position.Bottom:
+ case SettingsData.Position.BottomCenter:
+ const bottomBarOffset = barPos === SettingsData.Position.Bottom ? barOffset : 0;
+ const bottomDockOffset = SettingsData.dockPosition === SettingsData.Position.Bottom ? dockOffset : 0;
+ return Theme.snap(screenHeight - alignedHeight - margin - Math.max(bottomBarOffset, bottomDockOffset), dpr);
+ case SettingsData.Position.LeftCenter:
+ case SettingsData.Position.RightCenter:
+ default:
+ return Theme.snap(centerY, dpr);
+ }
+ }
+
+ anchors {
+ top: true
+ left: true
+ }
+
+ WlrLayershell.margins {
+ left: Math.max(0, Theme.snap(alignedX - shadowBuffer, dpr))
+ top: Math.max(0, Theme.snap(alignedY - shadowBuffer, dpr))
+ }
+
+ implicitWidth: alignedWidth + (shadowBuffer * 2)
+ implicitHeight: alignedHeight + (shadowBuffer * 2)
+
+ Timer {
+ id: hideTimer
+
+ interval: autoHideInterval
+ repeat: false
+ onTriggered: {
+ if (!enableMouseInteraction || !mouseArea.containsMouse) {
+ hide();
+ } else {
+ hideTimer.restart();
+ }
+ }
+ }
+
+ Timer {
+ id: closeTimer
+ interval: animationDuration + 50
+ onTriggered: {
+ if (!shouldBeVisible) {
+ visible = false;
+ osdHidden();
+ }
+ }
+ }
+
+ Item {
+ id: osdContainer
+ x: shadowBuffer
+ y: shadowBuffer
+ width: alignedWidth
+ height: alignedHeight
+ opacity: shouldBeVisible ? 1 : 0
+ scale: shouldBeVisible ? 1 : 0.9
+
+ property bool childHovered: false
+ readonly property real popupSurfaceAlpha: Theme.popupTransparency
+
+ Rectangle {
+ id: background
+ anchors.fill: parent
+ radius: Theme.cornerRadius
+ color: Theme.withAlpha(Theme.surfaceContainer, osdContainer.popupSurfaceAlpha)
+ border.color: BlurService.enabled ? BlurService.borderColor : Theme.outlineMedium
+ border.width: BlurService.enabled ? BlurService.borderWidth : 1
+ z: -1
+ }
+
+ ElevationShadow {
+ id: bgShadowLayer
+ anchors.fill: parent
+ visible: osdContainer.popupSurfaceAlpha >= 0.95
+ z: -1
+ level: Theme.elevationLevel3
+ fallbackOffset: 6
+ targetRadius: Theme.cornerRadius
+ targetColor: Theme.withAlpha(Theme.surfaceContainer, osdContainer.popupSurfaceAlpha)
+ borderColor: Theme.outlineMedium
+ borderWidth: 1
+ shadowEnabled: Theme.elevationEnabled && SettingsData.popoutElevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1"
+ layer.textureSize: Qt.size(Math.round(width * root.dpr), Math.round(height * root.dpr))
+ layer.textureMirroring: ShaderEffectSource.MirrorVertically
+ }
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+ hoverEnabled: enableMouseInteraction
+ acceptedButtons: Qt.NoButton
+ propagateComposedEvents: true
+ z: -1
+ onContainsMouseChanged: updateHoverState()
+ }
+
+ onChildHoveredChanged: updateHoverState()
+
+ Loader {
+ id: contentLoader
+ anchors.fill: parent
+ active: root.visible
+ asynchronous: false
+ }
+
+ Behavior on opacity {
+ NumberAnimation {
+ duration: animationDuration
+ easing.type: animationEasing
+ }
+ }
+
+ Behavior on scale {
+ NumberAnimation {
+ duration: animationDuration
+ easing.type: animationEasing
+ }
+ }
+ }
+
+ mask: Region {
+ item: bgShadowLayer
+ }
+}