diff --git a/quickshell/Common/SettingsData.qml b/quickshell/Common/SettingsData.qml index d7341a4c..75fcdca0 100644 --- a/quickshell/Common/SettingsData.qml +++ b/quickshell/Common/SettingsData.qml @@ -167,6 +167,10 @@ Singleton { onEnableRippleEffectsChanged: saveSettings() property bool m3ElevationEnabled: true onM3ElevationEnabledChanged: saveSettings() + property bool modalElevationEnabled: true + onModalElevationEnabledChanged: saveSettings() + property bool popoutElevationEnabled: true + onPopoutElevationEnabledChanged: saveSettings() property string wallpaperFillMode: "Fill" property bool blurredWallpaperLayer: false property bool blurWallpaperOnOverview: false diff --git a/quickshell/Common/Theme.qml b/quickshell/Common/Theme.qml index f9aeac78..733bc201 100644 --- a/quickshell/Common/Theme.qml +++ b/quickshell/Common/Theme.qml @@ -674,16 +674,55 @@ Singleton { property color shadowStrong: Qt.rgba(0, 0, 0, 0.3) readonly property bool elevationEnabled: typeof SettingsData !== "undefined" && (SettingsData.m3ElevationEnabled ?? true) - readonly property real elevationBlurMax: 64 - readonly property var elevationLevel1: ({ blurPx: 4, offsetY: 1, spreadPx: 0, alpha: 0.2 }) - readonly property var elevationLevel2: ({ blurPx: 8, offsetY: 4, spreadPx: 0, alpha: 0.25 }) - readonly property var elevationLevel3: ({ blurPx: 12, offsetY: 6, spreadPx: 0, alpha: 0.3 }) - readonly property var elevationLevel4: ({ blurPx: 16, offsetY: 8, spreadPx: 0, alpha: 0.3 }) - readonly property var elevationLevel5: ({ blurPx: 20, offsetY: 10, spreadPx: 0, alpha: 0.3 }) + readonly property real elevationBlurMax: 16 + readonly property var elevationLevel1: ({ + blurPx: 4, + offsetY: 1, + spreadPx: 0, + alpha: 0.2 + }) + readonly property var elevationLevel2: ({ + blurPx: 8, + offsetY: 4, + spreadPx: 0, + alpha: 0.25 + }) + readonly property var elevationLevel3: ({ + blurPx: 12, + offsetY: 6, + spreadPx: 0, + alpha: 0.3 + }) + readonly property var elevationLevel4: ({ + blurPx: 16, + offsetY: 8, + spreadPx: 0, + alpha: 0.3 + }) + readonly property var elevationLevel5: ({ + blurPx: 20, + offsetY: 10, + spreadPx: 0, + alpha: 0.3 + }) function elevationShadowColor(level) { const alpha = (level && level.alpha !== undefined) ? level.alpha : 0.3; - const baseColor = isLightMode ? Qt.rgba(0, 0, 0, 1) : surfaceContainerHighest; - return Theme.withAlpha(baseColor, alpha * (typeof SettingsData !== "undefined" ? SettingsData.popupTransparency : 1)); + return Qt.rgba(0, 0, 0, alpha); + } + function elevationTintOpacity(level) { + if (!level) + return 0; + if (level === elevationLevel1) + return 0.05; + if (level === elevationLevel2) + return 0.08; + if (level === elevationLevel3) + return 0.11; + if (level === elevationLevel4) + return 0.12; + if (level === elevationLevel5) + return 0.14; + return 0.08; } readonly property var animationDurations: [ diff --git a/quickshell/Common/settings/SettingsSpec.js b/quickshell/Common/settings/SettingsSpec.js index d56c4ed1..c14def72 100644 --- a/quickshell/Common/settings/SettingsSpec.js +++ b/quickshell/Common/settings/SettingsSpec.js @@ -47,6 +47,8 @@ var SPEC = { modalCustomAnimationDuration: { def: 150 }, enableRippleEffects: { def: true }, m3ElevationEnabled: { def: true }, + modalElevationEnabled: { def: true }, + popoutElevationEnabled: { def: true }, wallpaperFillMode: { def: "Fill" }, blurredWallpaperLayer: { def: false }, blurWallpaperOnOverview: { def: false }, diff --git a/quickshell/Modals/Common/DankModal.qml b/quickshell/Modals/Common/DankModal.qml index 4186fb67..731b8531 100644 --- a/quickshell/Modals/Common/DankModal.qml +++ b/quickshell/Modals/Common/DankModal.qml @@ -35,7 +35,7 @@ Item { property color borderColor: Theme.outlineMedium property real borderWidth: 1 property real cornerRadius: Theme.cornerRadius - property bool enableShadow: false + property bool enableShadow: true property alias modalFocusScope: focusScope property bool shouldBeVisible: false property bool shouldHaveFocus: shouldBeVisible @@ -143,7 +143,7 @@ Item { } } - readonly property real shadowBuffer: 5 + readonly property real shadowBuffer: 24 readonly property real alignedWidth: Theme.px(modalWidth, dpr) readonly property real alignedHeight: Theme.px(modalHeight, dpr) @@ -381,13 +381,10 @@ Item { readonly property var elev: Theme.elevationLevel3 readonly property real shadowBlurNorm: Math.max(0, Math.min(1, (elev && elev.blurPx !== undefined ? elev.blurPx : 12) / Theme.elevationBlurMax)) - Rectangle { - id: modalShadowShape + Item { + id: modalShadowLayer anchors.fill: parent - radius: root.cornerRadius - color: "black" - visible: false - layer.enabled: root.enableShadow && Theme.elevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1" + layer.enabled: root.enableShadow && Theme.elevationEnabled && SettingsData.modalElevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1" layer.smooth: false layer.effect: MultiEffect { @@ -395,20 +392,27 @@ Item { shadowEnabled: true blurEnabled: false maskEnabled: false - shadowBlur: modalShadowShape.parent.shadowBlurNorm + shadowBlur: animatedContent.shadowBlurNorm shadowScale: 1 - shadowVerticalOffset: modalShadowShape.parent.elev && modalShadowShape.parent.elev.offsetY !== undefined ? modalShadowShape.parent.elev.offsetY : 6 + shadowVerticalOffset: animatedContent.elev && animatedContent.elev.offsetY !== undefined ? animatedContent.elev.offsetY : 6 shadowHorizontalOffset: 0 shadowColor: Theme.elevationShadowColor(Theme.elevationLevel3) } + + Rectangle { + anchors.fill: parent + radius: root.cornerRadius + color: root.backgroundColor + border.color: root.borderColor + border.width: root.borderWidth + } } Rectangle { anchors.fill: parent - color: root.backgroundColor - border.color: root.borderColor - border.width: root.borderWidth radius: root.cornerRadius + color: Theme.surfaceTint + opacity: Theme.elevationEnabled ? Theme.elevationTintOpacity(Theme.elevationLevel3) : 0 } FocusScope { diff --git a/quickshell/Modals/DankLauncherV2/DankLauncherV2Modal.qml b/quickshell/Modals/DankLauncherV2/DankLauncherV2Modal.qml index 9668b7d7..dece12bd 100644 --- a/quickshell/Modals/DankLauncherV2/DankLauncherV2Modal.qml +++ b/quickshell/Modals/DankLauncherV2/DankLauncherV2Modal.qml @@ -1,4 +1,5 @@ import QtQuick +import QtQuick.Effects import Quickshell import Quickshell.Wayland import Quickshell.Hyprland @@ -390,12 +391,37 @@ Item { } } + Item { + id: launcherShadowLayer + anchors.fill: parent + layer.enabled: Theme.elevationEnabled && SettingsData.modalElevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1" + layer.smooth: false + layer.effect: MultiEffect { + autoPaddingEnabled: true + shadowEnabled: true + blurEnabled: false + maskEnabled: false + shadowBlur: Math.max(0, Math.min(1, Theme.elevationLevel3.blurPx / Theme.elevationBlurMax)) + shadowScale: 1 + shadowVerticalOffset: Theme.elevationLevel3.offsetY + shadowHorizontalOffset: 0 + shadowColor: Theme.elevationShadowColor(Theme.elevationLevel3) + } + + Rectangle { + anchors.fill: parent + color: root.backgroundColor + border.color: root.borderColor + border.width: root.borderWidth + radius: root.cornerRadius + } + } + Rectangle { anchors.fill: parent - color: root.backgroundColor - border.color: root.borderColor - border.width: root.borderWidth radius: root.cornerRadius + color: Theme.surfaceTint + opacity: Theme.elevationEnabled ? Theme.elevationTintOpacity(Theme.elevationLevel3) : 0 } MouseArea { diff --git a/quickshell/Modules/DankDash/WeatherTab.qml b/quickshell/Modules/DankDash/WeatherTab.qml index ce39b985..cc4d7771 100644 --- a/quickshell/Modules/DankDash/WeatherTab.qml +++ b/quickshell/Modules/DankDash/WeatherTab.qml @@ -814,12 +814,11 @@ Item { layer.enabled: true layer.effect: MultiEffect { - shadowEnabled: true + shadowEnabled: Theme.elevationEnabled shadowHorizontalOffset: 0 shadowVerticalOffset: 4 shadowBlur: 0.8 - shadowColor: Qt.rgba(0, 0, 0, 0.2) - shadowOpacity: 0.2 + shadowColor: Theme.elevationShadowColor(Theme.elevationLevel2) } } @@ -836,12 +835,11 @@ Item { layer.enabled: true layer.effect: MultiEffect { - shadowEnabled: true + shadowEnabled: Theme.elevationEnabled shadowHorizontalOffset: 0 shadowVerticalOffset: 4 shadowBlur: 0.8 - shadowColor: Qt.rgba(0, 0, 0, 0.2) - shadowOpacity: 0.2 + shadowColor: Theme.elevationShadowColor(Theme.elevationLevel2) } } } diff --git a/quickshell/Modules/Notifications/Center/HistoryNotificationCard.qml b/quickshell/Modules/Notifications/Center/HistoryNotificationCard.qml index 7e9e8bcb..6853c3e7 100644 --- a/quickshell/Modules/Notifications/Center/HistoryNotificationCard.qml +++ b/quickshell/Modules/Notifications/Center/HistoryNotificationCard.qml @@ -1,4 +1,5 @@ import QtQuick +import QtQuick.Effects import Quickshell import qs.Common import qs.Services @@ -32,6 +33,20 @@ Rectangle { radius: Theme.cornerRadius clip: true + layer.enabled: Theme.elevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1" + layer.smooth: false + layer.effect: MultiEffect { + autoPaddingEnabled: true + shadowEnabled: Theme.elevationEnabled + blurEnabled: false + maskEnabled: false + shadowBlur: Math.max(0, Math.min(1, Theme.elevationLevel1.blurPx / Theme.elevationBlurMax)) + shadowScale: 1 + shadowVerticalOffset: Theme.elevationLevel1.offsetY + shadowHorizontalOffset: 0 + shadowColor: Theme.elevationShadowColor(Theme.elevationLevel1) + } + color: { if (isSelected && keyboardNavigationActive) return Theme.primaryPressed; diff --git a/quickshell/Modules/Notifications/Center/NotificationCard.qml b/quickshell/Modules/Notifications/Center/NotificationCard.qml index af16d986..ff595d23 100644 --- a/quickshell/Modules/Notifications/Center/NotificationCard.qml +++ b/quickshell/Modules/Notifications/Center/NotificationCard.qml @@ -1,5 +1,6 @@ import QtQuick import QtQuick.Controls +import QtQuick.Effects import Quickshell import Quickshell.Services.Notifications import qs.Common @@ -99,6 +100,20 @@ Rectangle { } clip: true + layer.enabled: Theme.elevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1" + layer.smooth: false + layer.effect: MultiEffect { + autoPaddingEnabled: true + shadowEnabled: Theme.elevationEnabled + blurEnabled: false + maskEnabled: false + shadowBlur: Math.max(0, Math.min(1, Theme.elevationLevel1.blurPx / Theme.elevationBlurMax)) + shadowScale: 1 + shadowVerticalOffset: Theme.elevationLevel1.offsetY + shadowHorizontalOffset: 0 + shadowColor: Theme.elevationShadowColor(Theme.elevationLevel1) + } + HoverHandler { id: cardHoverHandler } diff --git a/quickshell/Modules/Notifications/Popup/NotificationPopup.qml b/quickshell/Modules/Notifications/Popup/NotificationPopup.qml index ea3123bb..8c8c400a 100644 --- a/quickshell/Modules/Notifications/Popup/NotificationPopup.qml +++ b/quickshell/Modules/Notifications/Popup/NotificationPopup.qml @@ -341,7 +341,7 @@ PanelWindow { layer.textureSize: Qt.size(Math.round(width * win.dpr), Math.round(height * win.dpr)) layer.textureMirroring: ShaderEffectSource.MirrorVertically - readonly property int blurMax: 64 + readonly property int blurMax: Theme.elevationBlurMax layer.effect: MultiEffect { id: shadowFx @@ -391,6 +391,13 @@ PanelWindow { } } } + + Rectangle { + anchors.fill: parent + radius: shadowShapeSource.radius + color: Theme.surfaceTint + opacity: Theme.elevationEnabled ? Theme.elevationTintOpacity(content.elevLevel) : 0 + } } Item { diff --git a/quickshell/Modules/Settings/ThemeColorsTab.qml b/quickshell/Modules/Settings/ThemeColorsTab.qml index 9764f157..8824dc18 100644 --- a/quickshell/Modules/Settings/ThemeColorsTab.qml +++ b/quickshell/Modules/Settings/ThemeColorsTab.qml @@ -1602,6 +1602,28 @@ Item { checked: SettingsData.m3ElevationEnabled ?? true onToggled: checked => SettingsData.set("m3ElevationEnabled", checked) } + + SettingsToggleRow { + tab: "theme" + tags: ["elevation", "shadow", "modal", "dialog", "m3"] + settingKey: "modalElevationEnabled" + text: I18n.tr("Modal Shadows") + description: I18n.tr("Shadow elevation on modals and dialogs") + checked: SettingsData.modalElevationEnabled ?? true + visible: SettingsData.m3ElevationEnabled ?? true + onToggled: checked => SettingsData.set("modalElevationEnabled", checked) + } + + SettingsToggleRow { + tab: "theme" + tags: ["elevation", "shadow", "popout", "popup", "osd", "dropdown", "m3"] + settingKey: "popoutElevationEnabled" + text: I18n.tr("Popout Shadows") + description: I18n.tr("Shadow elevation on popouts, OSDs, and dropdowns") + checked: SettingsData.popoutElevationEnabled ?? true + visible: SettingsData.m3ElevationEnabled ?? true + onToggled: checked => SettingsData.set("popoutElevationEnabled", checked) + } } SettingsCard { diff --git a/quickshell/Widgets/DankDropdown.qml b/quickshell/Widgets/DankDropdown.qml index d9eff353..7163ff4a 100644 --- a/quickshell/Widgets/DankDropdown.qml +++ b/quickshell/Widgets/DankDropdown.qml @@ -263,12 +263,19 @@ Item { layer.enabled: true layer.effect: MultiEffect { - shadowEnabled: Theme.elevationEnabled + shadowEnabled: Theme.elevationEnabled && SettingsData.popoutElevationEnabled shadowBlur: Theme.elevationEnabled ? Math.max(0, Math.min(1, (Theme.elevationLevel2 && Theme.elevationLevel2.blurPx !== undefined ? Theme.elevationLevel2.blurPx : 8) / Theme.elevationBlurMax)) : 0 shadowColor: Theme.elevationShadowColor(Theme.elevationLevel2) shadowVerticalOffset: Theme.elevationLevel2 && Theme.elevationLevel2.offsetY !== undefined ? Theme.elevationLevel2.offsetY : 4 } + Rectangle { + anchors.fill: parent + radius: Theme.cornerRadius + color: Theme.surfaceTint + opacity: Theme.elevationEnabled ? Theme.elevationTintOpacity(Theme.elevationLevel2) : 0 + } + Column { anchors.fill: parent anchors.margins: Theme.spacingS diff --git a/quickshell/Widgets/DankOSD.qml b/quickshell/Widgets/DankOSD.qml index d803b8fd..9e5ab901 100644 --- a/quickshell/Widgets/DankOSD.qml +++ b/quickshell/Widgets/DankOSD.qml @@ -278,7 +278,7 @@ PanelWindow { id: bgShadowLayer anchors.fill: parent visible: osdContainer.popupSurfaceAlpha >= 0.95 - layer.enabled: Theme.elevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1" + layer.enabled: Theme.elevationEnabled && SettingsData.popoutElevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1" layer.smooth: false layer.textureSize: Qt.size(Math.round(width * root.dpr), Math.round(height * root.dpr)) layer.textureMirroring: ShaderEffectSource.MirrorVertically @@ -293,10 +293,7 @@ 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)) - shadowColor: { - const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest; - return Theme.withAlpha(baseColor, osdContainer.effectiveShadowAlpha); - } + shadowColor: Theme.elevationShadowColor(Theme.elevationLevel3) } Rectangle { @@ -306,6 +303,13 @@ PanelWindow { border.color: Theme.outlineMedium border.width: 1 } + + Rectangle { + anchors.fill: parent + radius: Theme.cornerRadius + color: Theme.surfaceTint + opacity: Theme.elevationEnabled ? Theme.elevationTintOpacity(Theme.elevationLevel3) : 0 + } } MouseArea { diff --git a/quickshell/Widgets/DankPopout.qml b/quickshell/Widgets/DankPopout.qml index 2576ed29..bbe6273a 100644 --- a/quickshell/Widgets/DankPopout.qml +++ b/quickshell/Widgets/DankPopout.qml @@ -197,7 +197,7 @@ Item { readonly property real screenHeight: screen ? screen.height : 0 readonly property real dpr: screen ? screen.devicePixelRatio : 1 - readonly property real shadowBuffer: 5 + readonly property real shadowBuffer: 24 readonly property real alignedWidth: Theme.px(popupWidth, dpr) readonly property real alignedHeight: Theme.px(popupHeight, dpr) @@ -487,7 +487,6 @@ Item { height: parent.height radius: Theme.cornerRadius color: "black" - visible: false opacity: contentWrapper.opacity scale: contentWrapper.scale x: contentWrapper.x @@ -501,7 +500,7 @@ Item { readonly property real effectiveShadowAlpha: Math.max(0, Math.min(1, shadowBaseAlpha * popupSurfaceAlpha)) readonly property int blurMax: Theme.elevationBlurMax - layer.enabled: Theme.elevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1" && !(root.suspendShadowWhileResizing && root._resizeActive) + layer.enabled: Theme.elevationEnabled && SettingsData.popoutElevationEnabled && Quickshell.env("DMS_DISABLE_LAYER") !== "true" && Quickshell.env("DMS_DISABLE_LAYER") !== "1" && !(root.suspendShadowWhileResizing && root._resizeActive) layer.smooth: false layer.effect: MultiEffect { @@ -548,6 +547,13 @@ Item { border.width: 1 } + Rectangle { + anchors.fill: parent + radius: Theme.cornerRadius + color: Theme.surfaceTint + opacity: Theme.elevationEnabled ? Theme.elevationTintOpacity(Theme.elevationLevel3) : 0 + } + Loader { id: contentLoader anchors.fill: parent