From 36951f82c65df255330831f1b483590f10bbb6f2 Mon Sep 17 00:00:00 2001 From: purian23 Date: Sat, 28 Feb 2026 17:54:03 -0500 Subject: [PATCH] Implement Auto-Bar location aware shadowing --- quickshell/Common/SettingsData.qml | 2 + quickshell/Common/Theme.qml | 138 +++++++++++++++++- quickshell/Common/settings/SettingsSpec.js | 1 + quickshell/Modals/Common/DankModal.qml | 4 +- .../DankLauncherV2/DankLauncherV2Modal.qml | 4 +- quickshell/Modules/DankBar/BarCanvas.qml | 44 ++++-- quickshell/Modules/DankBar/Widgets/Media.qml | 10 +- .../Modules/DankBar/Widgets/SystemTrayBar.qml | 4 + .../Modules/DankBar/Widgets/SystemUpdate.qml | 5 +- .../Modules/DankDash/MediaDropdownOverlay.qml | 12 +- .../Modules/DankDash/MediaPlayerTab.qml | 4 +- quickshell/Modules/DankDash/WeatherTab.qml | 12 +- .../Center/HistoryNotificationCard.qml | 4 +- .../Notifications/Center/NotificationCard.qml | 12 +- .../Notifications/Popup/NotificationPopup.qml | 19 ++- quickshell/Modules/Settings/AboutTab.qml | 3 +- quickshell/Modules/Settings/DankBarTab.qml | 75 ++++++++++ .../Modules/Settings/ThemeColorsTab.qml | 37 +++++ .../Modules/Settings/TimeWeatherTab.qml | 4 +- quickshell/Modules/Toast.qml | 4 +- .../WorkspaceOverlays/OverviewWidget.qml | 4 +- quickshell/Widgets/DankDropdown.qml | 3 +- quickshell/Widgets/DankIconPicker.qml | 4 +- quickshell/Widgets/DankOSD.qml | 2 + quickshell/Widgets/DankPopout.qml | 37 ++++- 25 files changed, 388 insertions(+), 60 deletions(-) diff --git a/quickshell/Common/SettingsData.qml b/quickshell/Common/SettingsData.qml index 9fc0029c..949b6c59 100644 --- a/quickshell/Common/SettingsData.qml +++ b/quickshell/Common/SettingsData.qml @@ -173,6 +173,8 @@ Singleton { onM3ElevationOpacityChanged: saveSettings() property string m3ElevationColorMode: "default" onM3ElevationColorModeChanged: saveSettings() + property string m3ElevationLightDirection: "top" + onM3ElevationLightDirectionChanged: saveSettings() property string m3ElevationCustomColor: "#000000" onM3ElevationCustomColorChanged: saveSettings() property bool modalElevationEnabled: true diff --git a/quickshell/Common/Theme.qml b/quickshell/Common/Theme.qml index b420ccb4..c3b60b3d 100644 --- a/quickshell/Common/Theme.qml +++ b/quickshell/Common/Theme.qml @@ -678,38 +678,166 @@ Singleton { readonly property real _elevMult: typeof SettingsData !== "undefined" && SettingsData.m3ElevationIntensity !== undefined ? SettingsData.m3ElevationIntensity / 12 : 1 readonly property real _opMult: typeof SettingsData !== "undefined" && SettingsData.m3ElevationOpacity !== undefined ? SettingsData.m3ElevationOpacity / 60 : 1 + function normalizeElevationDirection(direction) { + switch (direction) { + case "top": + case "topLeft": + case "topRight": + case "bottom": + case "bottomLeft": + case "bottomRight": + case "left": + case "right": + case "autoBar": + return direction; + default: + return "top"; + } + } + + readonly property string elevationLightDirection: { + if (typeof SettingsData === "undefined" || !SettingsData.m3ElevationLightDirection) + return "top"; + switch (SettingsData.m3ElevationLightDirection) { + case "autoBar": + case "top": + case "topLeft": + case "topRight": + case "bottom": + return SettingsData.m3ElevationLightDirection; + default: + return "top"; + } + } + readonly property real _elevDiagRatio: 0.55 + readonly property string _globalElevationDirForTokens: { + const normalized = normalizeElevationDirection(elevationLightDirection); + return normalized === "autoBar" ? "top" : normalized; + } + readonly property real _elevDirX: { + switch (_globalElevationDirForTokens) { + case "topLeft": + case "bottomLeft": + case "left": + return 1; + case "topRight": + case "bottomRight": + case "right": + return -1; + default: + return 0; + } + } + readonly property real _elevDirY: { + switch (_globalElevationDirForTokens) { + case "bottom": + case "bottomLeft": + case "bottomRight": + return -1; + case "left": + case "right": + return 0; + default: + return 1; + } + } + readonly property real _elevDirXScale: (_globalElevationDirForTokens === "left" || _globalElevationDirForTokens === "right") ? 1 : _elevDiagRatio readonly property var elevationLevel1: ({ blurPx: 4 * _elevMult, - offsetY: 1 * _elevMult, + offsetX: 1 * _elevMult * _elevDirXScale * _elevDirX, + offsetY: 1 * _elevMult * _elevDirY, spreadPx: 0, alpha: 0.2 * _opMult }) readonly property var elevationLevel2: ({ blurPx: 8 * _elevMult, - offsetY: 4 * _elevMult, + offsetX: 4 * _elevMult * _elevDirXScale * _elevDirX, + offsetY: 4 * _elevMult * _elevDirY, spreadPx: 0, alpha: 0.25 * _opMult }) readonly property var elevationLevel3: ({ blurPx: 12 * _elevMult, - offsetY: 6 * _elevMult, + offsetX: 6 * _elevMult * _elevDirXScale * _elevDirX, + offsetY: 6 * _elevMult * _elevDirY, spreadPx: 0, alpha: 0.3 * _opMult }) readonly property var elevationLevel4: ({ blurPx: 16 * _elevMult, - offsetY: 8 * _elevMult, + offsetX: 8 * _elevMult * _elevDirXScale * _elevDirX, + offsetY: 8 * _elevMult * _elevDirY, spreadPx: 0, alpha: 0.3 * _opMult }) readonly property var elevationLevel5: ({ blurPx: 20 * _elevMult, - offsetY: 10 * _elevMult, + offsetX: 10 * _elevMult * _elevDirXScale * _elevDirX, + offsetY: 10 * _elevMult * _elevDirY, spreadPx: 0, alpha: 0.3 * _opMult }) + function elevationOffsetMagnitude(level, fallback, direction) { + if (!level) { + return fallback !== undefined ? Math.abs(fallback) : 0; + } + const yMag = Math.abs(level.offsetY !== undefined ? level.offsetY : 0); + if (yMag > 0) + return yMag; + const xMag = Math.abs(level.offsetX !== undefined ? level.offsetX : 0); + if (xMag > 0) { + if (direction === "left" || direction === "right") + return xMag; + return xMag / _elevDiagRatio; + } + return fallback !== undefined ? Math.abs(fallback) : 0; + } + + function elevationOffsetXFor(level, direction, fallback) { + const dir = normalizeElevationDirection(direction || elevationLightDirection); + const mag = elevationOffsetMagnitude(level, fallback, dir); + switch (dir) { + case "topLeft": + case "bottomLeft": + return mag * _elevDiagRatio; + case "topRight": + case "bottomRight": + return -mag * _elevDiagRatio; + case "left": + return mag; + case "right": + return -mag; + default: + return 0; + } + } + + function elevationOffsetYFor(level, direction, fallback) { + const dir = normalizeElevationDirection(direction || elevationLightDirection); + const mag = elevationOffsetMagnitude(level, fallback, dir); + switch (dir) { + case "bottom": + case "bottomLeft": + case "bottomRight": + return -mag; + case "left": + case "right": + return 0; + default: + return mag; + } + } + + function elevationOffsetX(level, fallback) { + return elevationOffsetXFor(level, elevationLightDirection, fallback); + } + + function elevationOffsetY(level, fallback) { + return elevationOffsetYFor(level, elevationLightDirection, fallback); + } + function elevationShadowColor(level) { const alpha = (level && level.alpha !== undefined) ? level.alpha : 0.3; let r = 0; diff --git a/quickshell/Common/settings/SettingsSpec.js b/quickshell/Common/settings/SettingsSpec.js index 898cf921..871dce13 100644 --- a/quickshell/Common/settings/SettingsSpec.js +++ b/quickshell/Common/settings/SettingsSpec.js @@ -50,6 +50,7 @@ var SPEC = { m3ElevationIntensity: { def: 12 }, m3ElevationOpacity: { def: 30 }, m3ElevationColorMode: { def: "default" }, + m3ElevationLightDirection: { def: "top" }, m3ElevationCustomColor: { def: "#000000" }, modalElevationEnabled: { def: true }, popoutElevationEnabled: { def: true }, diff --git a/quickshell/Modals/Common/DankModal.qml b/quickshell/Modals/Common/DankModal.qml index 50cd0f5e..8e767e4a 100644 --- a/quickshell/Modals/Common/DankModal.qml +++ b/quickshell/Modals/Common/DankModal.qml @@ -393,8 +393,8 @@ Item { maskEnabled: false shadowBlur: animatedContent.shadowBlurNorm shadowScale: 1 - shadowVerticalOffset: animatedContent.elev && animatedContent.elev.offsetY !== undefined ? animatedContent.elev.offsetY : 6 - shadowHorizontalOffset: 0 + shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel3, 6) + shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel3) blurMax: Theme.elevationBlurMax shadowColor: Theme.elevationShadowColor(Theme.elevationLevel3) } diff --git a/quickshell/Modals/DankLauncherV2/DankLauncherV2Modal.qml b/quickshell/Modals/DankLauncherV2/DankLauncherV2Modal.qml index fa6e9d95..17c4d46c 100644 --- a/quickshell/Modals/DankLauncherV2/DankLauncherV2Modal.qml +++ b/quickshell/Modals/DankLauncherV2/DankLauncherV2Modal.qml @@ -402,8 +402,8 @@ Item { maskEnabled: false shadowBlur: Math.max(0, Math.min(1, Theme.elevationLevel3.blurPx / Theme.elevationBlurMax)) shadowScale: 1 - shadowVerticalOffset: Theme.elevationLevel3.offsetY - shadowHorizontalOffset: 0 + shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel3, 6) + shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel3) blurMax: Theme.elevationBlurMax shadowColor: Theme.elevationShadowColor(Theme.elevationLevel3) } diff --git a/quickshell/Modules/DankBar/BarCanvas.qml b/quickshell/Modules/DankBar/BarCanvas.qml index 1dcfbd56..57d7ad35 100644 --- a/quickshell/Modules/DankBar/BarCanvas.qml +++ b/quickshell/Modules/DankBar/BarCanvas.qml @@ -56,9 +56,33 @@ Item { // M3 elevation shadow — Level 2 baseline (navigation bar), with per-bar override support readonly property bool hasPerBarOverride: (barConfig?.shadowIntensity ?? 0) > 0 readonly property var elevLevel: Theme.elevationLevel2 - readonly property bool shadowEnabled: (Theme.elevationEnabled - && (typeof SettingsData !== "undefined" ? (SettingsData.barElevationEnabled ?? true) : false)) - || hasPerBarOverride + readonly property bool shadowEnabled: (Theme.elevationEnabled && (typeof SettingsData !== "undefined" ? (SettingsData.barElevationEnabled ?? true) : false)) || hasPerBarOverride + readonly property string autoBarShadowDirection: isTop ? "top" : (isBottom ? "bottom" : (isLeft ? "left" : (isRight ? "right" : "top"))) + readonly property string globalShadowDirection: Theme.elevationLightDirection === "autoBar" ? autoBarShadowDirection : Theme.elevationLightDirection + readonly property string perBarShadowDirectionMode: barConfig?.shadowDirectionMode ?? "inherit" + readonly property string perBarManualShadowDirection: { + switch (barConfig?.shadowDirection) { + case "top": + case "topLeft": + case "topRight": + case "bottom": + return barConfig.shadowDirection; + default: + return "top"; + } + } + readonly property string effectiveShadowDirection: { + if (!hasPerBarOverride) + return globalShadowDirection; + switch (perBarShadowDirectionMode) { + case "autoBar": + return autoBarShadowDirection; + case "manual": + return perBarManualShadowDirection === "autoBar" ? autoBarShadowDirection : perBarManualShadowDirection; + default: + return globalShadowDirection; + } + } // Per-bar override values (when barConfig.shadowIntensity > 0) readonly property real overrideBlurPx: (barConfig?.shadowIntensity ?? 0) * 0.2 @@ -82,12 +106,10 @@ Item { // Resolved values — per-bar override wins if set, otherwise use global M3 elevation readonly property real shadowBlurPx: hasPerBarOverride ? overrideBlurPx : (elevLevel.blurPx ?? 8) readonly property real shadowBlur: Math.max(0, Math.min(1, shadowBlurPx / Theme.elevationBlurMax)) - readonly property color shadowColor: hasPerBarOverride - ? Theme.withAlpha(overrideBaseColor, overrideOpacity) - : Theme.elevationShadowColor(elevLevel) - readonly property real shadowOffsetY: hasPerBarOverride - ? overrideBlurPx * 0.5 - : (elevLevel.offsetY ?? 4) + readonly property color shadowColor: hasPerBarOverride ? Theme.withAlpha(overrideBaseColor, overrideOpacity) : Theme.elevationShadowColor(elevLevel) + readonly property real shadowOffsetMagnitude: hasPerBarOverride ? (overrideBlurPx * 0.5) : Theme.elevationOffsetMagnitude(elevLevel, 4, effectiveShadowDirection) + readonly property real shadowOffsetX: Theme.elevationOffsetXFor(hasPerBarOverride ? null : elevLevel, effectiveShadowDirection, shadowOffsetMagnitude) + readonly property real shadowOffsetY: Theme.elevationOffsetYFor(hasPerBarOverride ? null : elevLevel, effectiveShadowDirection, shadowOffsetMagnitude) readonly property string mainPath: generatePathForPosition(width, height) readonly property string borderFullPath: generateBorderFullPath(width, height) @@ -148,8 +170,8 @@ Item { shadowBlur: root.shadowBlur blurMax: Theme.elevationBlurMax shadowColor: root.shadowColor - shadowVerticalOffset: root.isTop ? root.shadowOffsetY : (root.isBottom ? -root.shadowOffsetY : 0) - shadowHorizontalOffset: root.isLeft ? root.shadowOffsetY : (root.isRight ? -root.shadowOffsetY : 0) + shadowVerticalOffset: root.shadowOffsetY + shadowHorizontalOffset: root.shadowOffsetX autoPaddingEnabled: true } diff --git a/quickshell/Modules/DankBar/Widgets/Media.qml b/quickshell/Modules/DankBar/Widgets/Media.qml index 61c71276..c7d6aac9 100644 --- a/quickshell/Modules/DankBar/Widgets/Media.qml +++ b/quickshell/Modules/DankBar/Widgets/Media.qml @@ -178,8 +178,9 @@ BasePill { if (root.popoutTarget && root.popoutTarget.setTriggerPosition) { const globalPos = parent.mapToItem(null, 0, 0); const currentScreen = root.parentScreen || Screen; - const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, root.barThickness, parent.width); - root.popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, root.section, currentScreen); + const barPosition = root.axis?.edge === "left" ? 2 : (root.axis?.edge === "right" ? 3 : (root.axis?.edge === "top" ? 0 : 1)); + const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, root.barThickness, parent.width, root.barSpacing, barPosition, root.barConfig); + root.popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, root.section, currentScreen, barPosition, root.barThickness, root.barSpacing, root.barConfig); } root.clicked(); } @@ -334,8 +335,9 @@ BasePill { if (root.popoutTarget && root.popoutTarget.setTriggerPosition) { const globalPos = mapToItem(null, 0, 0); const currentScreen = root.parentScreen || Screen; - const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, root.barThickness, root.width); - root.popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, root.section, currentScreen); + const barPosition = root.axis?.edge === "left" ? 2 : (root.axis?.edge === "right" ? 3 : (root.axis?.edge === "top" ? 0 : 1)); + const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, root.barThickness, root.width, root.barSpacing, barPosition, root.barConfig); + root.popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, root.section, currentScreen, barPosition, root.barThickness, root.barSpacing, root.barConfig); } root.clicked(); } diff --git a/quickshell/Modules/DankBar/Widgets/SystemTrayBar.qml b/quickshell/Modules/DankBar/Widgets/SystemTrayBar.qml index 5bf10048..c2375de0 100644 --- a/quickshell/Modules/DankBar/Widgets/SystemTrayBar.qml +++ b/quickshell/Modules/DankBar/Widgets/SystemTrayBar.qml @@ -982,6 +982,8 @@ BasePill { maskEnabled: false shadowBlur: Math.max(0, Math.min(1, menuContainer.shadowBlurPx / bgShadowLayer.blurMax)) shadowScale: 1 + (2 * menuContainer.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height)) + shadowHorizontalOffset: Theme.elevationOffsetX(menuContainer.elev) + shadowVerticalOffset: Theme.elevationOffsetY(menuContainer.elev, 4) shadowColor: { const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest; return Theme.withAlpha(baseColor, menuContainer.effectiveShadowAlpha); @@ -1454,6 +1456,8 @@ BasePill { maskEnabled: false shadowBlur: Math.max(0, Math.min(1, menuContainer.shadowBlurPx / menuBgShadowLayer.blurMax)) shadowScale: 1 + (2 * menuContainer.shadowSpreadPx) / Math.max(1, Math.min(menuBgShadowLayer.width, menuBgShadowLayer.height)) + shadowHorizontalOffset: Theme.elevationOffsetX(menuContainer.elev) + shadowVerticalOffset: Theme.elevationOffsetY(menuContainer.elev, 4) shadowColor: { const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest; return Theme.withAlpha(baseColor, menuContainer.effectiveShadowAlpha); diff --git a/quickshell/Modules/DankBar/Widgets/SystemUpdate.qml b/quickshell/Modules/DankBar/Widgets/SystemUpdate.qml index f03d1ecc..696c76c8 100644 --- a/quickshell/Modules/DankBar/Widgets/SystemUpdate.qml +++ b/quickshell/Modules/DankBar/Widgets/SystemUpdate.qml @@ -177,8 +177,9 @@ BasePill { if (popoutTarget && popoutTarget.setTriggerPosition) { const globalPos = root.visualContent.mapToItem(null, 0, 0); const currentScreen = parentScreen || Screen; - const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, root.visualWidth); - popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen); + const barPosition = root.axis?.edge === "left" ? 2 : (root.axis?.edge === "right" ? 3 : (root.axis?.edge === "top" ? 0 : 1)); + const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, root.visualWidth, root.barSpacing, barPosition, root.barConfig); + popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen, barPosition, barThickness, root.barSpacing, root.barConfig); } root.clicked(); } diff --git a/quickshell/Modules/DankDash/MediaDropdownOverlay.qml b/quickshell/Modules/DankDash/MediaDropdownOverlay.qml index 8fcaa906..4646c436 100644 --- a/quickshell/Modules/DankDash/MediaDropdownOverlay.qml +++ b/quickshell/Modules/DankDash/MediaDropdownOverlay.qml @@ -98,8 +98,8 @@ Item { layer.effect: MultiEffect { autoPaddingEnabled: true shadowEnabled: Theme.elevationEnabled - shadowHorizontalOffset: 0 - shadowVerticalOffset: Theme.elevationLevel2 && Theme.elevationLevel2.offsetY !== undefined ? Theme.elevationLevel2.offsetY : 4 + shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel2) + shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel2, 4) shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel2 && Theme.elevationLevel2.blurPx !== undefined ? Theme.elevationLevel2.blurPx : 8) / Theme.elevationBlurMax)) : 0 blurMax: Theme.elevationBlurMax shadowColor: Theme.elevationShadowColor(Theme.elevationLevel2) @@ -248,8 +248,8 @@ Item { layer.effect: MultiEffect { autoPaddingEnabled: true shadowEnabled: Theme.elevationEnabled - shadowHorizontalOffset: 0 - shadowVerticalOffset: Theme.elevationLevel2 && Theme.elevationLevel2.offsetY !== undefined ? Theme.elevationLevel2.offsetY : 4 + shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel2) + shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel2, 4) shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel2 && Theme.elevationLevel2.blurPx !== undefined ? Theme.elevationLevel2.blurPx : 8) / Theme.elevationBlurMax)) : 0 blurMax: Theme.elevationBlurMax shadowColor: Theme.elevationShadowColor(Theme.elevationLevel2) @@ -414,8 +414,8 @@ Item { layer.effect: MultiEffect { autoPaddingEnabled: true shadowEnabled: Theme.elevationEnabled - shadowHorizontalOffset: 0 - shadowVerticalOffset: Theme.elevationLevel2 && Theme.elevationLevel2.offsetY !== undefined ? Theme.elevationLevel2.offsetY : 4 + shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel2) + shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel2, 4) shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel2 && Theme.elevationLevel2.blurPx !== undefined ? Theme.elevationLevel2.blurPx : 8) / Theme.elevationBlurMax)) : 0 blurMax: Theme.elevationBlurMax shadowColor: Theme.elevationShadowColor(Theme.elevationLevel2) diff --git a/quickshell/Modules/DankDash/MediaPlayerTab.qml b/quickshell/Modules/DankDash/MediaPlayerTab.qml index 6943dd09..052e2814 100644 --- a/quickshell/Modules/DankDash/MediaPlayerTab.qml +++ b/quickshell/Modules/DankDash/MediaPlayerTab.qml @@ -532,8 +532,8 @@ Item { layer.enabled: Theme.elevationEnabled layer.effect: MultiEffect { shadowEnabled: Theme.elevationEnabled - shadowHorizontalOffset: 0 - shadowVerticalOffset: Theme.elevationLevel1 && Theme.elevationLevel1.offsetY !== undefined ? Theme.elevationLevel1.offsetY : 1 + shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel1) + shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel1, 1) shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel1 && Theme.elevationLevel1.blurPx !== undefined ? Theme.elevationLevel1.blurPx : 4) / Theme.elevationBlurMax)) : 0 blurMax: Theme.elevationBlurMax shadowColor: Theme.elevationShadowColor(Theme.elevationLevel1) diff --git a/quickshell/Modules/DankDash/WeatherTab.qml b/quickshell/Modules/DankDash/WeatherTab.qml index dce69570..f7be2c6e 100644 --- a/quickshell/Modules/DankDash/WeatherTab.qml +++ b/quickshell/Modules/DankDash/WeatherTab.qml @@ -244,8 +244,8 @@ Item { layer.enabled: Theme.elevationEnabled layer.effect: MultiEffect { shadowEnabled: Theme.elevationEnabled - shadowHorizontalOffset: 0 - shadowVerticalOffset: Theme.elevationLevel1 && Theme.elevationLevel1.offsetY !== undefined ? Theme.elevationLevel1.offsetY : 1 + shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel1) + shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel1, 1) shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel1 && Theme.elevationLevel1.blurPx !== undefined ? Theme.elevationLevel1.blurPx : 4) / Theme.elevationBlurMax)) : 0 blurMax: Theme.elevationBlurMax shadowColor: Theme.elevationShadowColor(Theme.elevationLevel1) @@ -816,8 +816,8 @@ Item { layer.enabled: Theme.elevationEnabled layer.effect: MultiEffect { shadowEnabled: Theme.elevationEnabled - shadowHorizontalOffset: 0 - shadowVerticalOffset: Theme.elevationLevel2 && Theme.elevationLevel2.offsetY !== undefined ? Theme.elevationLevel2.offsetY : 4 + shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel2) + shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel2, 4) shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel2 && Theme.elevationLevel2.blurPx !== undefined ? Theme.elevationLevel2.blurPx : 8) / Theme.elevationBlurMax)) : 0 blurMax: Theme.elevationBlurMax shadowColor: Theme.elevationShadowColor(Theme.elevationLevel2) @@ -838,8 +838,8 @@ Item { layer.enabled: Theme.elevationEnabled layer.effect: MultiEffect { shadowEnabled: Theme.elevationEnabled - shadowHorizontalOffset: 0 - shadowVerticalOffset: Theme.elevationLevel2 && Theme.elevationLevel2.offsetY !== undefined ? Theme.elevationLevel2.offsetY : 4 + shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel2) + shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel2, 4) shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel2 && Theme.elevationLevel2.blurPx !== undefined ? Theme.elevationLevel2.blurPx : 8) / Theme.elevationBlurMax)) : 0 blurMax: Theme.elevationBlurMax shadowColor: Theme.elevationShadowColor(Theme.elevationLevel2) diff --git a/quickshell/Modules/Notifications/Center/HistoryNotificationCard.qml b/quickshell/Modules/Notifications/Center/HistoryNotificationCard.qml index 11441536..c6e20bb6 100644 --- a/quickshell/Modules/Notifications/Center/HistoryNotificationCard.qml +++ b/quickshell/Modules/Notifications/Center/HistoryNotificationCard.qml @@ -47,8 +47,8 @@ Rectangle { maskEnabled: false shadowBlur: Math.max(0, Math.min(1, ((Theme.elevationLevel1 && Theme.elevationLevel1.blurPx !== undefined) ? Theme.elevationLevel1.blurPx : 4) / Theme.elevationBlurMax)) shadowScale: 1 - shadowVerticalOffset: (Theme.elevationLevel1 && Theme.elevationLevel1.offsetY !== undefined) ? Theme.elevationLevel1.offsetY : 1 - shadowHorizontalOffset: 0 + shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel1, 1) + shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel1) blurMax: Theme.elevationBlurMax shadowColor: Theme.elevationShadowColor(Theme.elevationLevel1) } diff --git a/quickshell/Modules/Notifications/Center/NotificationCard.qml b/quickshell/Modules/Notifications/Center/NotificationCard.qml index b90b877b..af364fbe 100644 --- a/quickshell/Modules/Notifications/Center/NotificationCard.qml +++ b/quickshell/Modules/Notifications/Center/NotificationCard.qml @@ -45,7 +45,8 @@ Rectangle { readonly property real baseShadowBlurPx: (shadowElevation && shadowElevation.blurPx !== undefined) ? shadowElevation.blurPx : 4 readonly property real hoverShadowBlurBoost: cardHoverHandler.hovered ? Math.min(2, baseShadowBlurPx * 0.25) : 0 property real shadowBlurPx: shadowsAllowed ? (baseShadowBlurPx + hoverShadowBlurBoost) : 0 - property real shadowOffsetYPx: shadowsAllowed ? (1 + (cardHoverHandler.hovered ? 0.35 : 0)) : 0 + property real shadowOffsetXPx: shadowsAllowed ? Theme.elevationOffsetX(shadowElevation) : 0 + property real shadowOffsetYPx: shadowsAllowed ? (Theme.elevationOffsetY(shadowElevation, 1) + (cardHoverHandler.hovered ? 0.35 : 0)) : 0 property bool __initialized: false Component.onCompleted: { @@ -70,6 +71,13 @@ Rectangle { } } + Behavior on shadowOffsetXPx { + NumberAnimation { + duration: Theme.shortDuration + easing.type: Theme.standardEasing + } + } + Behavior on shadowOffsetYPx { NumberAnimation { duration: Theme.shortDuration @@ -138,7 +146,7 @@ Rectangle { shadowBlur: Math.max(0, Math.min(1, root.shadowBlurPx / Theme.elevationBlurMax)) shadowScale: 1 shadowVerticalOffset: root.shadowOffsetYPx - shadowHorizontalOffset: 0 + shadowHorizontalOffset: root.shadowOffsetXPx blurMax: Theme.elevationBlurMax shadowColor: root.shadowElevation ? Theme.elevationShadowColor(root.shadowElevation) : "transparent" } diff --git a/quickshell/Modules/Notifications/Popup/NotificationPopup.qml b/quickshell/Modules/Notifications/Popup/NotificationPopup.qml index 82d0f82e..0fdf3194 100644 --- a/quickshell/Modules/Notifications/Popup/NotificationPopup.qml +++ b/quickshell/Modules/Notifications/Popup/NotificationPopup.qml @@ -185,8 +185,9 @@ PanelWindow { property bool isBottomCenter: SettingsData.notificationPopupPosition === SettingsData.Position.BottomCenter property bool isCenterPosition: isTopCenter || isBottomCenter readonly property real maxPopupShadowBlurPx: Math.max((Theme.elevationLevel3 && Theme.elevationLevel3.blurPx !== undefined) ? Theme.elevationLevel3.blurPx : 12, (Theme.elevationLevel4 && Theme.elevationLevel4.blurPx !== undefined) ? Theme.elevationLevel4.blurPx : 16) - readonly property real maxPopupShadowOffsetYPx: Math.max(Math.abs((Theme.elevationLevel3 && Theme.elevationLevel3.offsetY !== undefined) ? Theme.elevationLevel3.offsetY : 6), Math.abs((Theme.elevationLevel4 && Theme.elevationLevel4.offsetY !== undefined) ? Theme.elevationLevel4.offsetY : 8)) - readonly property real windowShadowPad: Theme.elevationEnabled && SettingsData.notificationPopupShadowEnabled ? Theme.snap(Math.max(16, maxPopupShadowBlurPx + maxPopupShadowOffsetYPx + 8), dpr) : 0 + readonly property real maxPopupShadowOffsetXPx: Math.max(Math.abs(Theme.elevationOffsetX(Theme.elevationLevel3)), Math.abs(Theme.elevationOffsetX(Theme.elevationLevel4))) + readonly property real maxPopupShadowOffsetYPx: Math.max(Math.abs(Theme.elevationOffsetY(Theme.elevationLevel3, 6)), Math.abs(Theme.elevationOffsetY(Theme.elevationLevel4, 8))) + readonly property real windowShadowPad: Theme.elevationEnabled && SettingsData.notificationPopupShadowEnabled ? Theme.snap(Math.max(16, maxPopupShadowBlurPx + Math.max(maxPopupShadowOffsetXPx, maxPopupShadowOffsetYPx) + 8), dpr) : 0 anchors.top: true anchors.left: true @@ -354,9 +355,10 @@ PanelWindow { readonly property bool shadowsAllowed: Theme.elevationEnabled && SettingsData.notificationPopupShadowEnabled readonly property var elevLevel: cardHoverHandler.hovered ? Theme.elevationLevel4 : Theme.elevationLevel3 readonly property real cardInset: Theme.snap(4, win.dpr) - readonly property real shadowRenderPadding: shadowsAllowed ? Theme.snap(Math.max(16, shadowBlurPx + Math.abs(shadowOffsetY) + 8), win.dpr) : 0 + readonly property real shadowRenderPadding: shadowsAllowed ? Theme.snap(Math.max(16, shadowBlurPx + Math.max(Math.abs(shadowOffsetX), Math.abs(shadowOffsetY)) + 8), win.dpr) : 0 property real shadowBlurPx: shadowsAllowed ? (elevLevel && elevLevel.blurPx !== undefined ? elevLevel.blurPx : 12) : 0 - property real shadowOffsetY: shadowsAllowed ? (elevLevel && elevLevel.offsetY !== undefined ? elevLevel.offsetY : 6) : 0 + property real shadowOffsetX: shadowsAllowed ? Theme.elevationOffsetX(elevLevel) : 0 + property real shadowOffsetY: shadowsAllowed ? Theme.elevationOffsetY(elevLevel, 6) : 0 Behavior on shadowBlurPx { NumberAnimation { @@ -365,6 +367,13 @@ PanelWindow { } } + Behavior on shadowOffsetX { + NumberAnimation { + duration: Theme.shortDuration + easing.type: Theme.standardEasing + } + } + Behavior on shadowOffsetY { NumberAnimation { duration: Theme.shortDuration @@ -390,7 +399,7 @@ PanelWindow { maskEnabled: false shadowBlur: Math.max(0, Math.min(1, content.shadowBlurPx / bgShadowLayer.blurMax)) shadowScale: 1 - shadowHorizontalOffset: 0 + shadowHorizontalOffset: content.shadowOffsetX shadowVerticalOffset: content.shadowOffsetY blurMax: Theme.elevationBlurMax shadowColor: content.shadowsAllowed && content.elevLevel ? Theme.elevationShadowColor(content.elevLevel) : "transparent" diff --git a/quickshell/Modules/Settings/AboutTab.qml b/quickshell/Modules/Settings/AboutTab.qml index 59268b55..d294a68b 100644 --- a/quickshell/Modules/Settings/AboutTab.qml +++ b/quickshell/Modules/Settings/AboutTab.qml @@ -882,7 +882,8 @@ Item { layer.effect: MultiEffect { shadowEnabled: Theme.elevationEnabled shadowOpacity: Theme.elevationLevel1 && Theme.elevationLevel1.alpha !== undefined ? Theme.elevationLevel1.alpha : 0.2 - shadowVerticalOffset: Theme.elevationLevel1 && Theme.elevationLevel1.offsetY !== undefined ? Theme.elevationLevel1.offsetY : 1 + shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel1) + shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel1, 1) shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel1 && Theme.elevationLevel1.blurPx !== undefined ? Theme.elevationLevel1.blurPx : 4) / Theme.elevationBlurMax)) : 0 blurMax: Theme.elevationBlurMax shadowColor: Theme.elevationShadowColor(Theme.elevationLevel1) diff --git a/quickshell/Modules/Settings/DankBarTab.qml b/quickshell/Modules/Settings/DankBarTab.qml index 13989591..ba54fb38 100644 --- a/quickshell/Modules/Settings/DankBarTab.qml +++ b/quickshell/Modules/Settings/DankBarTab.qml @@ -140,6 +140,8 @@ Item { scrollYBehavior: defaultBar.scrollYBehavior ?? "workspace", shadowIntensity: defaultBar.shadowIntensity ?? 0, shadowOpacity: defaultBar.shadowOpacity ?? 60, + shadowDirectionMode: defaultBar.shadowDirectionMode ?? "inherit", + shadowDirection: defaultBar.shadowDirection ?? "top", shadowColorMode: defaultBar.shadowColorMode ?? "default", shadowCustomColor: defaultBar.shadowCustomColor ?? "#000000" }; @@ -1053,6 +1055,7 @@ Item { readonly property bool shadowActive: (selectedBarConfig?.shadowIntensity ?? 0) > 0 readonly property bool isCustomColor: (selectedBarConfig?.shadowColorMode ?? "default") === "custom" + readonly property string directionSource: selectedBarConfig?.shadowDirectionMode ?? "inherit" StyledText { width: parent.width @@ -1107,6 +1110,78 @@ Item { }) } + SettingsDropdownRow { + visible: shadowCard.shadowActive + text: I18n.tr("Direction Source", "bar shadow direction source") + description: I18n.tr("Choose how this bar resolves shadow direction") + settingKey: "barShadowDirectionSource" + options: [I18n.tr("Inherit Global (Default)", "bar shadow direction source option"), I18n.tr("Auto (Bar-aware)", "bar shadow direction source option"), I18n.tr("Manual", "bar shadow direction source option")] + currentValue: { + switch (shadowCard.directionSource) { + case "autoBar": + return I18n.tr("Auto (Bar-aware)", "bar shadow direction source option"); + case "manual": + return I18n.tr("Manual", "bar shadow direction source option"); + default: + return I18n.tr("Inherit Global (Default)", "bar shadow direction source option"); + } + } + onValueChanged: value => { + if (value === I18n.tr("Auto (Bar-aware)", "bar shadow direction source option")) { + SettingsData.updateBarConfig(selectedBarId, { + shadowDirectionMode: "autoBar" + }); + } else if (value === I18n.tr("Manual", "bar shadow direction source option")) { + SettingsData.updateBarConfig(selectedBarId, { + shadowDirectionMode: "manual" + }); + } else { + SettingsData.updateBarConfig(selectedBarId, { + shadowDirectionMode: "inherit" + }); + } + } + } + + SettingsDropdownRow { + visible: shadowCard.shadowActive && shadowCard.directionSource === "manual" + text: I18n.tr("Manual Direction", "bar manual shadow direction") + description: I18n.tr("Use a fixed shadow direction for this bar") + settingKey: "barShadowDirectionManual" + options: [I18n.tr("Top", "shadow direction option"), I18n.tr("Top Left", "shadow direction option"), I18n.tr("Top Right", "shadow direction option"), I18n.tr("Bottom", "shadow direction option")] + currentValue: { + switch (selectedBarConfig?.shadowDirection) { + case "topLeft": + return I18n.tr("Top Left", "shadow direction option"); + case "topRight": + return I18n.tr("Top Right", "shadow direction option"); + case "bottom": + return I18n.tr("Bottom", "shadow direction option"); + default: + return I18n.tr("Top", "shadow direction option"); + } + } + onValueChanged: value => { + if (value === I18n.tr("Top Left", "shadow direction option")) { + SettingsData.updateBarConfig(selectedBarId, { + shadowDirection: "topLeft" + }); + } else if (value === I18n.tr("Top Right", "shadow direction option")) { + SettingsData.updateBarConfig(selectedBarId, { + shadowDirection: "topRight" + }); + } else if (value === I18n.tr("Bottom", "shadow direction option")) { + SettingsData.updateBarConfig(selectedBarId, { + shadowDirection: "bottom" + }); + } else { + SettingsData.updateBarConfig(selectedBarId, { + shadowDirection: "top" + }); + } + } + } + Column { visible: shadowCard.shadowActive width: parent.width diff --git a/quickshell/Modules/Settings/ThemeColorsTab.qml b/quickshell/Modules/Settings/ThemeColorsTab.qml index 790ea4c3..7b389b40 100644 --- a/quickshell/Modules/Settings/ThemeColorsTab.qml +++ b/quickshell/Modules/Settings/ThemeColorsTab.qml @@ -1680,6 +1680,43 @@ Item { } } + SettingsDropdownRow { + tab: "theme" + tags: ["elevation", "shadow", "direction", "light", "advanced", "m3"] + settingKey: "m3ElevationLightDirection" + text: I18n.tr("Light Direction") + description: I18n.tr("Controls shadow cast direction for elevation layers") + options: [I18n.tr("Auto (Bar-aware)", "shadow direction option"), I18n.tr("Top (Default)", "shadow direction option"), I18n.tr("Top Left", "shadow direction option"), I18n.tr("Top Right", "shadow direction option"), I18n.tr("Bottom", "shadow direction option")] + currentValue: { + switch (SettingsData.m3ElevationLightDirection) { + case "autoBar": + return I18n.tr("Auto (Bar-aware)", "shadow direction option"); + case "topLeft": + return I18n.tr("Top Left", "shadow direction option"); + case "topRight": + return I18n.tr("Top Right", "shadow direction option"); + case "bottom": + return I18n.tr("Bottom", "shadow direction option"); + default: + return I18n.tr("Top (Default)", "shadow direction option"); + } + } + visible: SettingsData.m3ElevationEnabled ?? true + onValueChanged: value => { + if (value === I18n.tr("Auto (Bar-aware)", "shadow direction option")) { + SettingsData.set("m3ElevationLightDirection", "autoBar"); + } else if (value === I18n.tr("Top Left", "shadow direction option")) { + SettingsData.set("m3ElevationLightDirection", "topLeft"); + } else if (value === I18n.tr("Top Right", "shadow direction option")) { + SettingsData.set("m3ElevationLightDirection", "topRight"); + } else if (value === I18n.tr("Bottom", "shadow direction option")) { + SettingsData.set("m3ElevationLightDirection", "bottom"); + } else { + SettingsData.set("m3ElevationLightDirection", "top"); + } + } + } + Item { visible: (SettingsData.m3ElevationEnabled ?? true) && SettingsData.m3ElevationColorMode === "custom" width: parent.width diff --git a/quickshell/Modules/Settings/TimeWeatherTab.qml b/quickshell/Modules/Settings/TimeWeatherTab.qml index 35b0be5c..ca73ec32 100644 --- a/quickshell/Modules/Settings/TimeWeatherTab.qml +++ b/quickshell/Modules/Settings/TimeWeatherTab.qml @@ -666,8 +666,8 @@ Item { layer.enabled: Theme.elevationEnabled layer.effect: MultiEffect { shadowEnabled: Theme.elevationEnabled - shadowHorizontalOffset: 0 - shadowVerticalOffset: Theme.elevationLevel1 && Theme.elevationLevel1.offsetY !== undefined ? Theme.elevationLevel1.offsetY : 1 + shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel1) + shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel1, 1) shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel1 && Theme.elevationLevel1.blurPx !== undefined ? Theme.elevationLevel1.blurPx : 4) / Theme.elevationBlurMax)) : 0 blurMax: Theme.elevationBlurMax shadowColor: Theme.elevationShadowColor(Theme.elevationLevel1) diff --git a/quickshell/Modules/Toast.qml b/quickshell/Modules/Toast.qml index 21d584d0..d74518f8 100644 --- a/quickshell/Modules/Toast.qml +++ b/quickshell/Modules/Toast.qml @@ -409,8 +409,8 @@ PanelWindow { layer.effect: MultiEffect { autoPaddingEnabled: true shadowEnabled: Theme.elevationEnabled - shadowHorizontalOffset: 0 - shadowVerticalOffset: Theme.elevationLevel3 && Theme.elevationLevel3.offsetY !== undefined ? Theme.elevationLevel3.offsetY : 6 + shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel3) + shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel3, 6) shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel3 && Theme.elevationLevel3.blurPx !== undefined ? Theme.elevationLevel3.blurPx : 12) / Theme.elevationBlurMax)) : 0 blurMax: Theme.elevationBlurMax shadowColor: Theme.elevationShadowColor(Theme.elevationLevel3) diff --git a/quickshell/Modules/WorkspaceOverlays/OverviewWidget.qml b/quickshell/Modules/WorkspaceOverlays/OverviewWidget.qml index 7f141ac0..b8c8564c 100644 --- a/quickshell/Modules/WorkspaceOverlays/OverviewWidget.qml +++ b/quickshell/Modules/WorkspaceOverlays/OverviewWidget.qml @@ -157,8 +157,8 @@ Item { layer.effect: MultiEffect { shadowEnabled: Theme.elevationEnabled shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel2 && Theme.elevationLevel2.blurPx !== undefined ? Theme.elevationLevel2.blurPx : 8) / Theme.elevationBlurMax)) : 0 - shadowHorizontalOffset: 0 - shadowVerticalOffset: Theme.elevationLevel2 && Theme.elevationLevel2.offsetY !== undefined ? Theme.elevationLevel2.offsetY : 4 + shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel2) + shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel2, 4) blurMax: Theme.elevationBlurMax shadowColor: Theme.elevationShadowColor(Theme.elevationLevel2) shadowOpacity: Theme.elevationLevel2 && Theme.elevationLevel2.alpha !== undefined ? Theme.elevationLevel2.alpha : 0.25 diff --git a/quickshell/Widgets/DankDropdown.qml b/quickshell/Widgets/DankDropdown.qml index ad218add..5293d2be 100644 --- a/quickshell/Widgets/DankDropdown.qml +++ b/quickshell/Widgets/DankDropdown.qml @@ -277,7 +277,8 @@ Item { shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel2 && Theme.elevationLevel2.blurPx !== undefined ? Theme.elevationLevel2.blurPx : 8) / Theme.elevationBlurMax)) : 0 blurMax: Theme.elevationBlurMax shadowColor: Theme.elevationShadowColor(Theme.elevationLevel2) - shadowVerticalOffset: Theme.elevationLevel2 && Theme.elevationLevel2.offsetY !== undefined ? Theme.elevationLevel2.offsetY : 4 + shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel2) + shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel2, 4) } Rectangle { diff --git a/quickshell/Widgets/DankIconPicker.qml b/quickshell/Widgets/DankIconPicker.qml index 077a99c0..4f99cc49 100644 --- a/quickshell/Widgets/DankIconPicker.qml +++ b/quickshell/Widgets/DankIconPicker.qml @@ -148,8 +148,8 @@ Rectangle { blurMax: Theme.elevationBlurMax shadowColor: Theme.elevationShadowColor(Theme.elevationLevel2) shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel2 && Theme.elevationLevel2.blurPx !== undefined ? Theme.elevationLevel2.blurPx : 8) / Theme.elevationBlurMax)) : 0 - shadowHorizontalOffset: 0 - shadowVerticalOffset: Theme.elevationLevel2 && Theme.elevationLevel2.offsetY !== undefined ? Theme.elevationLevel2.offsetY : 4 + shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel2) + shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel2, 4) shadowOpacity: Theme.elevationLevel2 && Theme.elevationLevel2.alpha !== undefined ? Theme.elevationLevel2.alpha : 0.25 } diff --git a/quickshell/Widgets/DankOSD.qml b/quickshell/Widgets/DankOSD.qml index 499ed5f0..993f0189 100644 --- a/quickshell/Widgets/DankOSD.qml +++ b/quickshell/Widgets/DankOSD.qml @@ -292,6 +292,8 @@ PanelWindow { maskEnabled: false shadowBlur: Math.max(0, Math.min(1, osdContainer.shadowBlurPx / bgShadowLayer.blurMax)) shadowScale: 1 + (2 * osdContainer.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height)) + shadowHorizontalOffset: Theme.elevationOffsetX(Theme.elevationLevel3) + shadowVerticalOffset: Theme.elevationOffsetY(Theme.elevationLevel3, 6) blurMax: Theme.elevationBlurMax shadowColor: Theme.elevationShadowColor(Theme.elevationLevel3) } diff --git a/quickshell/Widgets/DankPopout.qml b/quickshell/Widgets/DankPopout.qml index 538d7531..717f600d 100644 --- a/quickshell/Widgets/DankPopout.qml +++ b/quickshell/Widgets/DankPopout.qml @@ -78,6 +78,38 @@ Item { property int effectiveBarPosition: 0 property real effectiveBarBottomGap: 0 + readonly property string autoBarShadowDirection: { + const section = triggerSection || "center"; + switch (effectiveBarPosition) { + case SettingsData.Position.Top: + if (section === "left") + return "topLeft"; + if (section === "right") + return "topRight"; + return "top"; + case SettingsData.Position.Bottom: + if (section === "left") + return "bottomLeft"; + if (section === "right") + return "bottomRight"; + return "bottom"; + case SettingsData.Position.Left: + if (section === "left") + return "topLeft"; + if (section === "right") + return "bottomLeft"; + return "left"; + case SettingsData.Position.Right: + if (section === "left") + return "topRight"; + if (section === "right") + return "bottomRight"; + return "right"; + default: + return "top"; + } + } + readonly property string effectiveShadowDirection: Theme.elevationLightDirection === "autoBar" ? autoBarShadowDirection : Theme.elevationLightDirection // Snapshot mask geometry to prevent background damage on bar updates property real _frozenMaskX: 0 @@ -507,6 +539,8 @@ Item { property real shadowBlurPx: elev && elev.blurPx !== undefined ? elev.blurPx : 12 property real shadowSpreadPx: elev && elev.spreadPx !== undefined ? elev.spreadPx : 0 property real shadowBaseAlpha: elev && elev.alpha !== undefined ? elev.alpha : 0.3 + property real shadowOffsetX: Theme.elevationOffsetXFor(Theme.elevationLevel3, root.effectiveShadowDirection, 6) + property real shadowOffsetY: Theme.elevationOffsetYFor(Theme.elevationLevel3, root.effectiveShadowDirection, 6) readonly property real popupSurfaceAlpha: SettingsData.popupTransparency readonly property real effectiveShadowAlpha: Math.max(0, Math.min(1, shadowBaseAlpha * popupSurfaceAlpha)) readonly property int blurMax: Theme.elevationBlurMax @@ -521,7 +555,8 @@ Item { maskEnabled: false shadowBlur: Math.max(0, Math.min(1, shadowSource.shadowBlurPx / shadowSource.blurMax)) shadowScale: 1 + (2 * shadowSource.shadowSpreadPx) / Math.max(1, Math.min(shadowSource.width, shadowSource.height)) - shadowVerticalOffset: parent.elev && parent.elev.offsetY !== undefined ? parent.elev.offsetY : 6 + shadowHorizontalOffset: shadowSource.shadowOffsetX + shadowVerticalOffset: shadowSource.shadowOffsetY blurMax: Theme.elevationBlurMax shadowColor: Theme.elevationShadowColor(Theme.elevationLevel3) }