From 03a985228ded14055b4724120d218e1cafc9a7f9 Mon Sep 17 00:00:00 2001 From: bbedward Date: Mon, 5 Jan 2026 13:43:15 -0500 Subject: [PATCH] dankbar: add shadow option fixes #916 --- quickshell/Common/SettingsData.qml | 6 +- quickshell/Common/settings/SettingsSpec.js | 6 +- quickshell/Modules/DankBar/BarCanvas.qml | 62 ++++++++++ quickshell/Modules/Settings/DankBarTab.qml | 128 ++++++++++++++++++++- 4 files changed, 199 insertions(+), 3 deletions(-) diff --git a/quickshell/Common/SettingsData.qml b/quickshell/Common/SettingsData.qml index f20669a7..9246c987 100644 --- a/quickshell/Common/SettingsData.qml +++ b/quickshell/Common/SettingsData.qml @@ -444,7 +444,11 @@ Singleton { "maximizeDetection": true, "scrollEnabled": true, "scrollXBehavior": "column", - "scrollYBehavior": "workspace" + "scrollYBehavior": "workspace", + "shadowIntensity": 0, + "shadowOpacity": 60, + "shadowColorMode": "text", + "shadowCustomColor": "#000000" } ] diff --git a/quickshell/Common/settings/SettingsSpec.js b/quickshell/Common/settings/SettingsSpec.js index 744f6c29..28ca9307 100644 --- a/quickshell/Common/settings/SettingsSpec.js +++ b/quickshell/Common/settings/SettingsSpec.js @@ -332,7 +332,11 @@ var SPEC = { maximizeDetection: true, scrollEnabled: true, scrollXBehavior: "column", - scrollYBehavior: "workspace" + scrollYBehavior: "workspace", + shadowIntensity: 0, + shadowOpacity: 60, + shadowColorMode: "text", + shadowCustomColor: "#000000" }], onChange: "updateBarConfigs" }, desktopClockEnabled: { def: false }, diff --git a/quickshell/Modules/DankBar/BarCanvas.qml b/quickshell/Modules/DankBar/BarCanvas.qml index 681b5c27..ab0bdf97 100644 --- a/quickshell/Modules/DankBar/BarCanvas.qml +++ b/quickshell/Modules/DankBar/BarCanvas.qml @@ -1,4 +1,5 @@ import QtQuick +import QtQuick.Effects import QtQuick.Shapes import qs.Common import qs.Services @@ -52,6 +53,29 @@ Item { } } + readonly property real shadowIntensity: barConfig?.shadowIntensity ?? 0 + readonly property bool shadowEnabled: shadowIntensity > 0 + readonly property int blurMax: 64 + readonly property real shadowBlurPx: shadowIntensity * 0.2 + readonly property real shadowBlur: Math.max(0, Math.min(1, shadowBlurPx / blurMax)) + readonly property real shadowOpacity: (barConfig?.shadowOpacity ?? 60) / 100 + readonly property string shadowColorMode: barConfig?.shadowColorMode ?? "text" + readonly property color shadowBaseColor: { + switch (shadowColorMode) { + case "surface": + return Theme.surface; + case "primary": + return Theme.primary; + case "secondary": + return Theme.secondary; + case "custom": + return barConfig?.shadowCustomColor ?? "#000000"; + default: + return Theme.surfaceText; + } + } + readonly property color shadowColor: Theme.withAlpha(shadowBaseColor, shadowOpacity * barWindow._backgroundAlpha) + readonly property string mainPath: generatePathForPosition(width, height) readonly property string borderFullPath: generateBorderFullPath(width, height) readonly property string borderEdgePath: generateBorderEdgePath(width, height) @@ -94,6 +118,44 @@ Item { } } + Loader { + id: shadowLoader + anchors.fill: parent + active: root.shadowEnabled && mainPathCorrectShape + asynchronous: false + sourceComponent: Item { + anchors.fill: parent + + layer.enabled: true + layer.smooth: true + layer.samples: 8 + layer.textureSize: Qt.size(Math.round(width * barWindow._dpr * 2), Math.round(height * barWindow._dpr * 2)) + layer.effect: MultiEffect { + shadowEnabled: true + shadowBlur: root.shadowBlur + shadowColor: root.shadowColor + shadowVerticalOffset: root.isTop ? root.shadowBlurPx * 0.5 : (root.isBottom ? -root.shadowBlurPx * 0.5 : 0) + shadowHorizontalOffset: root.isLeft ? root.shadowBlurPx * 0.5 : (root.isRight ? -root.shadowBlurPx * 0.5 : 0) + autoPaddingEnabled: true + } + + Shape { + anchors.fill: parent + preferredRendererType: Shape.CurveRenderer + + ShapePath { + fillColor: barWindow._bgColor + strokeColor: "transparent" + strokeWidth: 0 + + PathSvg { + path: root.mainPath + } + } + } + } + } + Loader { id: barShape anchors.fill: parent diff --git a/quickshell/Modules/Settings/DankBarTab.qml b/quickshell/Modules/Settings/DankBarTab.qml index 89428bb0..5ee46c0e 100644 --- a/quickshell/Modules/Settings/DankBarTab.qml +++ b/quickshell/Modules/Settings/DankBarTab.qml @@ -241,7 +241,11 @@ Item { maximizeDetection: defaultBar.maximizeDetection ?? true, scrollEnabled: defaultBar.scrollEnabled ?? true, scrollXBehavior: defaultBar.scrollXBehavior ?? "column", - scrollYBehavior: defaultBar.scrollYBehavior ?? "workspace" + scrollYBehavior: defaultBar.scrollYBehavior ?? "workspace", + shadowIntensity: defaultBar.shadowIntensity ?? 0, + shadowOpacity: defaultBar.shadowOpacity ?? 60, + shadowColorMode: defaultBar.shadowColorMode ?? "text", + shadowCustomColor: defaultBar.shadowCustomColor ?? "#000000" }; SettingsData.addBarConfig(newBar); selectedBarId = newId; @@ -1052,6 +1056,128 @@ Item { } } + SettingsCard { + iconName: "layers" + title: I18n.tr("Shadow", "bar shadow settings card") + visible: selectedBarConfig?.enabled + + readonly property bool shadowActive: (selectedBarConfig?.shadowIntensity ?? 0) > 0 + readonly property bool isCustomColor: (selectedBarConfig?.shadowColorMode ?? "text") === "custom" + + SettingsSliderRow { + text: I18n.tr("Intensity", "shadow intensity slider") + minimum: 0 + maximum: 100 + unit: "%" + value: selectedBarConfig?.shadowIntensity ?? 0 + onSliderValueChanged: newValue => SettingsData.updateBarConfig(selectedBarId, { + shadowIntensity: newValue + }) + } + + SettingsSliderRow { + visible: parent.shadowActive + text: I18n.tr("Opacity") + minimum: 10 + maximum: 100 + unit: "%" + value: selectedBarConfig?.shadowOpacity ?? 60 + onSliderValueChanged: newValue => SettingsData.updateBarConfig(selectedBarId, { + shadowOpacity: newValue + }) + } + + Column { + visible: parent.shadowActive + width: parent.width + spacing: Theme.spacingS + + StyledText { + text: I18n.tr("Color") + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceText + x: Theme.spacingM + } + + Item { + width: parent.width + height: shadowColorGroup.implicitHeight + + DankButtonGroup { + id: shadowColorGroup + anchors.horizontalCenter: parent.horizontalCenter + buttonPadding: parent.width < 420 ? Theme.spacingXS : Theme.spacingS + minButtonWidth: parent.width < 420 ? 36 : 56 + textSize: parent.width < 420 ? Theme.fontSizeSmall : Theme.fontSizeMedium + model: [I18n.tr("Text", "shadow color option"), I18n.tr("Surface", "shadow color option"), I18n.tr("Primary"), I18n.tr("Secondary"), I18n.tr("Custom")] + selectionMode: "single" + currentIndex: { + switch (selectedBarConfig?.shadowColorMode || "text") { + case "surface": + return 1; + case "primary": + return 2; + case "secondary": + return 3; + case "custom": + return 4; + default: + return 0; + } + } + onSelectionChanged: (index, selected) => { + if (!selected) + return; + let mode = "text"; + switch (index) { + case 1: + mode = "surface"; + break; + case 2: + mode = "primary"; + break; + case 3: + mode = "secondary"; + break; + case 4: + mode = "custom"; + break; + } + SettingsData.updateBarConfig(selectedBarId, { + shadowColorMode: mode + }); + } + } + } + + Rectangle { + visible: selectedBarConfig?.shadowColorMode === "custom" + width: 32 + height: 32 + radius: 16 + color: selectedBarConfig?.shadowCustomColor ?? "#000000" + border.color: Theme.outline + border.width: 1 + anchors.horizontalCenter: parent.horizontalCenter + + MouseArea { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + onClicked: { + PopoutService.colorPickerModal.selectedColor = selectedBarConfig?.shadowCustomColor ?? "#000000"; + PopoutService.colorPickerModal.pickerTitle = I18n.tr("Color"); + PopoutService.colorPickerModal.onColorSelectedCallback = function (color) { + SettingsData.updateBarConfig(selectedBarId, { + shadowCustomColor: color.toString() + }); + }; + PopoutService.colorPickerModal.show(); + } + } + } + } + } + SettingsToggleCard { iconName: "border_style" title: I18n.tr("Border")