From c8ec045a3cd2298606bb5faf531be0b07b4c1aea Mon Sep 17 00:00:00 2001 From: bbedward Date: Tue, 25 Aug 2026 15:54:57 -0400 Subject: [PATCH] bar/island: add background options for satellites, transparency, blur. Bigger click targets --- quickshell/Common/SettingsData.qml | 5 + quickshell/Common/settings/SettingsSpec.js | 5 + quickshell/Modules/DankBar/LeftSection.qml | 2 + quickshell/Modules/DankBar/RightSection.qml | 2 + quickshell/Modules/DankBar/WidgetHost.qml | 9 + .../Modules/DankIsland/DankIslandSurface.qml | 24 +- .../DankIsland/IslandSatelliteChrome.qml | 96 +++++++ .../DankIsland/IslandSatelliteHost.qml | 261 +++++++++++++++++- quickshell/Modules/Plugins/BasePill.qml | 5 +- quickshell/Modules/Settings/DankIslandTab.qml | 61 ++++ .../translations/settings_search_index.json | 101 +++++++ 11 files changed, 558 insertions(+), 13 deletions(-) create mode 100644 quickshell/Modules/DankIsland/IslandSatelliteChrome.qml diff --git a/quickshell/Common/SettingsData.qml b/quickshell/Common/SettingsData.qml index 6312409d3..f835ce9a2 100644 --- a/quickshell/Common/SettingsData.qml +++ b/quickshell/Common/SettingsData.qml @@ -995,6 +995,7 @@ Singleton { property int dankIslandHoverOpenDelay: 150 property int dankIslandHoverCloseDelay: 150 property string dankIslandPalette: "default" + property real dankIslandTransparency: 1 property bool dankIslandHighContrast: false property bool dankIslandMediaClockVisible: true property bool dankIslandHomeNotificationBadge: true @@ -1008,6 +1009,10 @@ Singleton { property bool dankIslandSatellitesEnabled: true property string dankIslandSatellitePosition: "edges" property int dankIslandSatelliteGap: 12 + property bool dankIslandSatelliteBackground: false + property bool dankIslandSatelliteGothCorners: true + property real dankIslandSatelliteTransparency: 1 + property int dankIslandSatelliteSwoopRadius: 24 property bool dankIslandReducedMotion: false property real dankIslandSpringStiffness: 560 property real dankIslandSpringDamping: 37 diff --git a/quickshell/Common/settings/SettingsSpec.js b/quickshell/Common/settings/SettingsSpec.js index d73fba99e..fa4725819 100644 --- a/quickshell/Common/settings/SettingsSpec.js +++ b/quickshell/Common/settings/SettingsSpec.js @@ -533,6 +533,7 @@ var SPEC = { dankIslandHoverOpenDelay: { def: 150 }, dankIslandHoverCloseDelay: { def: 150 }, dankIslandPalette: { def: "default" }, + dankIslandTransparency: { def: 1 }, dankIslandHighContrast: { def: false }, dankIslandMediaClockVisible: { def: true }, dankIslandHomeNotificationBadge: { def: true }, @@ -546,6 +547,10 @@ var SPEC = { dankIslandSatellitesEnabled: { def: true }, dankIslandSatellitePosition: { def: "edges" }, dankIslandSatelliteGap: { def: 12 }, + dankIslandSatelliteBackground: { def: false }, + dankIslandSatelliteGothCorners: { def: true }, + dankIslandSatelliteTransparency: { def: 1 }, + dankIslandSatelliteSwoopRadius: { def: 24 }, dankIslandReducedMotion: { def: false }, dankIslandSpringStiffness: { def: 560 }, dankIslandSpringDamping: { def: 37 }, diff --git a/quickshell/Modules/DankBar/LeftSection.qml b/quickshell/Modules/DankBar/LeftSection.qml index 92dbaefa3..63f21e545 100644 --- a/quickshell/Modules/DankBar/LeftSection.qml +++ b/quickshell/Modules/DankBar/LeftSection.qml @@ -20,6 +20,7 @@ Item { // False when a perpendicular bar occupies this edge, so the first widget's click area // doesn't extend past the bar into the neighbour (matters most in the frame surface). property bool edgeIsScreenEdge: true + property real crossEdgeExtension: 0 readonly property bool isVertical: overrideAxisLayout ? forceVerticalLayout : (axis?.isVertical ?? false) property alias widgetLayoutLoader: layoutLoader @@ -73,6 +74,7 @@ Item { sectionSpacing: parent.rowSpacing isLeftBarEdge: root.edgeIsScreenEdge isRightBarEdge: false + crossEdgeExtension: root.crossEdgeExtension } } } diff --git a/quickshell/Modules/DankBar/RightSection.qml b/quickshell/Modules/DankBar/RightSection.qml index 70fdcdff8..f1bb892e5 100644 --- a/quickshell/Modules/DankBar/RightSection.qml +++ b/quickshell/Modules/DankBar/RightSection.qml @@ -20,6 +20,7 @@ Item { // False when a perpendicular bar occupies this edge, so the last widget's click area // doesn't extend past the bar into the neighbour (matters most in the frame surface). property bool edgeIsScreenEdge: true + property real crossEdgeExtension: 0 readonly property bool isVertical: overrideAxisLayout ? forceVerticalLayout : (axis?.isVertical ?? false) property alias widgetLayoutLoader: layoutLoader @@ -75,6 +76,7 @@ Item { sectionSpacing: parent.rowSpacing isLeftBarEdge: false isRightBarEdge: root.edgeIsScreenEdge + crossEdgeExtension: root.crossEdgeExtension } } } diff --git a/quickshell/Modules/DankBar/WidgetHost.qml b/quickshell/Modules/DankBar/WidgetHost.qml index d864c6795..412869819 100644 --- a/quickshell/Modules/DankBar/WidgetHost.qml +++ b/quickshell/Modules/DankBar/WidgetHost.qml @@ -25,6 +25,7 @@ Loader { property bool isRightBarEdge: false property bool isTopBarEdge: false property bool isBottomBarEdge: false + property real crossEdgeExtension: 0 property string _registeredScreenName: "" property var _registeredItem: null @@ -183,6 +184,14 @@ Loader { restoreMode: Binding.RestoreNone } + Binding { + target: root.item + when: root.item && "crossEdgeExtension" in root.item + property: "crossEdgeExtension" + value: root.crossEdgeExtension + restoreMode: Binding.RestoreNone + } + onLoaded: { if (!item) return; diff --git a/quickshell/Modules/DankIsland/DankIslandSurface.qml b/quickshell/Modules/DankIsland/DankIslandSurface.qml index 37d7b772d..00630b700 100644 --- a/quickshell/Modules/DankIsland/DankIslandSurface.qml +++ b/quickshell/Modules/DankIsland/DankIslandSurface.qml @@ -37,6 +37,17 @@ Item { } return Theme.surfaceContainerHigh; } + readonly property bool popupStyled: root.controller.expanded + readonly property real compactOpacity: Math.max(0, Math.min(1, SettingsData.dankIslandTransparency)) + readonly property color effectiveSurfaceColor: { + if (root.highContrast) + return Theme.surfaceContainerHighest; + if (root.popupStyled) + return Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency); + return Theme.withAlpha(root.surfaceColor, root.compactOpacity); + } + readonly property real surfaceOpacity: root.effectiveSurfaceColor.a + readonly property real currentSurfaceRadius: Math.max(0, motion.currentTopLeftRadius, motion.currentBottomLeftRadius) signal scrollWheel(var wheel) @@ -212,9 +223,16 @@ Item { topRightRadius: Math.max(0, motion.currentTopRightRadius) bottomLeftRadius: Math.max(0, motion.currentBottomLeftRadius) bottomRightRadius: Math.max(0, motion.currentBottomRightRadius) - color: root.surfaceColor - border.width: root.highContrast ? 2 : 0 - border.color: root.highContrast ? Theme.outlineStrong : "transparent" + color: root.effectiveSurfaceColor + border.width: root.highContrast ? 2 : (root.popupStyled ? BlurService.borderWidth : 0) + border.color: root.highContrast ? Theme.outlineStrong : (root.popupStyled ? BlurService.borderColor : "transparent") + + Behavior on color { + ColorAnimation { + duration: root.reducedMotion ? 0 : Theme.shortDuration + easing.type: Easing.OutCubic + } + } MouseArea { anchors.fill: parent diff --git a/quickshell/Modules/DankIsland/IslandSatelliteChrome.qml b/quickshell/Modules/DankIsland/IslandSatelliteChrome.qml new file mode 100644 index 000000000..e8aa08625 --- /dev/null +++ b/quickshell/Modules/DankIsland/IslandSatelliteChrome.qml @@ -0,0 +1,96 @@ +import QtQuick +import QtQuick.Shapes +import qs.Common +import qs.Services + +Item { + id: root + + property bool rightSide: false + property bool bottomEdge: false + property color fillColor: "transparent" + property bool gothEnabled: true + property real sweep: 24 + property real bodyRadius: Theme.cornerRadius + property var parentScreen: null + + readonly property real cornerR: Math.max(0, Math.min(root.bodyRadius, root.height / 2)) + readonly property real sweepR: root.gothEnabled ? Math.max(0, Math.min(root.sweep, root.height - root.cornerR, root.width - root.cornerR)) : 0 + + readonly property string fillPath: { + root.width; + root.height; + root.cornerR; + root.sweepR; + root.rightSide; + root.bottomEdge; + return root.buildPath(); + } + + function buildPath() { + const w = root.width; + const h = root.height; + const cr = root.cornerR; + const s = root.sweepR; + if (root.bottomEdge) + return root.rightSide ? rightBottomPath(w, h, cr, s) : leftBottomPath(w, h, cr, s); + return root.rightSide ? rightTopPath(w, h, cr, s) : leftTopPath(w, h, cr, s); + } + + function leftTopPath(w, h, cr, s) { + if (s > 0) + return `M 0 0 L ${w + s} 0 A ${s} ${s} 0 0 0 ${w} ${s} L ${w} ${h - cr} A ${cr} ${cr} 0 0 1 ${w - cr} ${h} L ${s} ${h} A ${s} ${s} 0 0 0 0 ${h + s} Z`; + return `M 0 0 L ${w} 0 L ${w} ${h - cr} A ${cr} ${cr} 0 0 1 ${w - cr} ${h} L ${cr} ${h} A ${cr} ${cr} 0 0 1 0 ${h - cr} Z`; + } + + function rightTopPath(w, h, cr, s) { + if (s > 0) + return `M ${w} 0 L ${-s} 0 A ${s} ${s} 0 0 1 0 ${s} L 0 ${h - cr} A ${cr} ${cr} 0 0 0 ${cr} ${h} L ${w - s} ${h} A ${s} ${s} 0 0 1 ${w} ${h + s} Z`; + return `M ${w} 0 L 0 0 L 0 ${h - cr} A ${cr} ${cr} 0 0 0 ${cr} ${h} L ${w - cr} ${h} A ${cr} ${cr} 0 0 0 ${w} ${h - cr} Z`; + } + + function leftBottomPath(w, h, cr, s) { + if (s > 0) + return `M 0 ${h} L ${w + s} ${h} A ${s} ${s} 0 0 1 ${w} ${h - s} L ${w} ${cr} A ${cr} ${cr} 0 0 0 ${w - cr} 0 L ${s} 0 A ${s} ${s} 0 0 1 0 ${-s} Z`; + return `M 0 ${h} L ${w} ${h} L ${w} ${cr} A ${cr} ${cr} 0 0 0 ${w - cr} 0 L ${cr} 0 A ${cr} ${cr} 0 0 0 0 ${cr} Z`; + } + + function rightBottomPath(w, h, cr, s) { + if (s > 0) + return `M ${w} ${h} L ${-s} ${h} A ${s} ${s} 0 0 0 0 ${h - s} L 0 ${cr} A ${cr} ${cr} 0 0 1 ${cr} 0 L ${w - s} 0 A ${s} ${s} 0 0 0 ${w} ${-s} Z`; + return `M ${w} ${h} L 0 ${h} L 0 ${cr} A ${cr} ${cr} 0 0 1 ${cr} 0 L ${w - cr} 0 A ${cr} ${cr} 0 0 1 ${w} ${cr} Z`; + } + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton + onClicked: { + const activePopout = PopoutManager.getActivePopout(root.parentScreen); + if (activePopout) { + if (activePopout.dashVisible !== undefined) { + activePopout.dashVisible = false; + } else if (activePopout.notificationHistoryVisible !== undefined) { + activePopout.notificationHistoryVisible = false; + } else { + activePopout.close(); + } + } + TrayMenuManager.closeAllMenus(); + } + } + + Shape { + anchors.fill: parent + preferredRendererType: Shape.CurveRenderer + + ShapePath { + fillColor: root.fillColor + strokeColor: "transparent" + strokeWidth: 0 + + PathSvg { + path: root.fillPath + } + } + } +} diff --git a/quickshell/Modules/DankIsland/IslandSatelliteHost.qml b/quickshell/Modules/DankIsland/IslandSatelliteHost.qml index 94c3f3047..8c6c74d1e 100644 --- a/quickshell/Modules/DankIsland/IslandSatelliteHost.qml +++ b/quickshell/Modules/DankIsland/IslandSatelliteHost.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import Quickshell +import Quickshell.Wayland import qs.Common import qs.Modules.DankBar import qs.Services @@ -45,6 +46,31 @@ Item { readonly property bool bottomEdge: SettingsData.dankIslandEdge === "bottom" readonly property real rowInset: Theme.snap(Math.max(0, (root.controller.compactFaceHeight - root.barThickness) / 2), root.screenScale) readonly property real rowY: root.bottomEdge ? root.height - root.outerGap - root.rowInset - root.barThickness : root.outerGap + root.rowInset + readonly property bool backgroundEnabled: SettingsData.dankIslandSatelliteBackground + readonly property bool spanEdges: root.edgeAligned || root.backgroundEnabled + readonly property real chromePad: Theme.snap(root.innerPadding + Theme.spacingXS, root.screenScale) + readonly property real chromeInset: root.backgroundEnabled ? root.chromePad : 0 + readonly property real chromeY: root.bottomEdge ? root.rowY : 0 + readonly property real chromeHeight: root.bottomEdge ? root.height - root.rowY : root.rowY + root.barThickness + readonly property real crossEdgeExtension: root.spanEdges ? (root.bottomEdge ? root.height - root.rowY - root.barThickness : root.rowY) : 0 + readonly property bool gothCorners: SettingsData.dankIslandSatelliteGothCorners + readonly property real chromeOpacity: Math.max(0, Math.min(1, SettingsData.dankIslandSatelliteTransparency)) + readonly property real sweepRadius: Math.max(4, Math.min(64, SettingsData.dankIslandSatelliteSwoopRadius)) + readonly property color chromeBase: { + if (SettingsData.dankIslandHighContrast) + return Theme.surfaceContainerHighest; + switch (SettingsData.dankIslandPalette) { + case "bright": + return Theme.surfaceBright; + case "dim": + return Theme.surfaceDim; + } + return Theme.surfaceContainerHigh; + } + readonly property color chromeColor: Theme.withAlpha(root.chromeBase, root.chromeOpacity) + readonly property bool chromeTranslucent: root.backgroundEnabled && root.chromeOpacity > 0 && root.chromeOpacity < 1 + readonly property real islandOpacity: root.islandSurface?.surfaceOpacity ?? 1 + readonly property bool islandTranslucent: root.islandOpacity > 0 && root.islandOpacity < 1 readonly property bool tracksIsland: !root.edgeAligned && root.visible readonly property bool motionRunning: root.tracksIsland && (root.islandSurface?.motionRunning ?? false) readonly property real islandStartX: root.islandSurface?.motionStartBounds.x ?? 0 @@ -125,8 +151,190 @@ Item { signal colorPickerRequested function registerBlurWidget(item) { + root.registerBlurWidget(item); } function unregisterBlurWidget(item) { + root.unregisterBlurWidget(item); + } + } + + property var _blurWidgetItems: [] + property var _blurRegion: null + + function registerBlurWidget(item) { + if (root._blurWidgetItems.indexOf(item) >= 0) + return; + root._blurWidgetItems = root._blurWidgetItems.concat([item]); + blurRebuildTimer.restart(); + } + + function unregisterBlurWidget(item) { + const idx = root._blurWidgetItems.indexOf(item); + if (idx < 0) + return; + const arr = root._blurWidgetItems.slice(); + arr.splice(idx, 1); + root._blurWidgetItems = arr; + blurRebuildTimer.restart(); + } + + function rebuildBlur() { + const old = root._blurRegion; + if (old) { + root.hostWindow.BackgroundEffect.blurRegion = null; + root._blurRegion = null; + old.destroy(); + } + if (!BlurService.enabled) + return; + const widgets = root._blurWidgetItems.filter(w => w && w.visible && w.width > 0 && w.height > 0); + const chromes = [leftChrome, rightChrome].filter(c => root.chromeTranslucent && c.visible); + if (chromes.length === 0 && widgets.length === 0 && !root.islandTranslucent) + return; + const region = blurRegionComp.createObject(root.hostWindow); + if (!region) + return; + const subRegions = []; + if (root.islandTranslucent) { + const islandSub = blurIslandRegionComp.createObject(region); + if (islandSub) + subRegions.push(islandSub); + } + for (const chrome of chromes) { + const body = blurItemRegionComp.createObject(region, { + w: chrome + }); + if (body) + subRegions.push(body); + if (!root.gothCorners) + continue; + for (const isWing of [true, false]) { + const piece = blurSweepRegionComp.createObject(region, { + chrome: chrome, + isWing: isWing + }); + if (piece) + subRegions.push(piece); + } + } + for (const w of widgets) { + const sub = blurItemRegionComp.createObject(region, { + w: w + }); + if (sub) + subRegions.push(sub); + } + region.regions = subRegions; + root._blurRegion = region; + root.hostWindow.BackgroundEffect.blurRegion = region; + } + + onChromeTranslucentChanged: blurRebuildTimer.restart() + onGothCornersChanged: blurRebuildTimer.restart() + onIslandTranslucentChanged: blurRebuildTimer.restart() + Component.onCompleted: blurRebuildTimer.restart() + + Connections { + target: BlurService + + function onEnabledChanged() { + blurRebuildTimer.restart(); + } + } + + // Blur regions need republishing after geometry settles, same as WindowBlur's settle kicks + Connections { + target: root.islandSurface ?? null + + function onMotionRunningChanged() { + if (root.islandSurface.motionRunning) + return; + blurRebuildTimer.restart(); + blurTrailTimer.restart(); + } + } + + Timer { + id: blurTrailTimer + + interval: 96 + onTriggered: root.rebuildBlur() + } + + Component.onDestruction: { + if (root._blurRegion && root.hostWindow) + root.hostWindow.BackgroundEffect.blurRegion = null; + } + + Timer { + id: blurRebuildTimer + + interval: 1 + onTriggered: root.rebuildBlur() + } + + Component { + id: blurRegionComp + + Region {} + } + + Component { + id: blurItemRegionComp + + Region { + property Item w + + item: w + radius: Theme.cornerRadius + } + } + + Component { + id: blurIslandRegionComp + + Region { + x: root.islandSurface?.currentVisualX ?? 0 + y: root.islandSurface?.currentVisualY ?? 0 + width: root.islandSurface?.currentVisualWidth ?? 0 + height: root.islandSurface?.currentVisualHeight ?? 0 + radius: root.islandSurface?.currentSurfaceRadius ?? 0 + } + } + + Component { + id: blurSweepRegionComp + + // s×s square at a chrome corner minus a quarter-disc — the fillet the chrome paints + Region { + id: piece + + property Item chrome + property bool isWing + + readonly property real s: piece.chrome.sweepR + + x: { + if (piece.isWing) + return piece.chrome.rightSide ? piece.chrome.x + piece.chrome.width - piece.s : piece.chrome.x; + return piece.chrome.rightSide ? piece.chrome.x - piece.s : piece.chrome.x + piece.chrome.width; + } + y: { + if (piece.isWing) + return piece.chrome.bottomEdge ? piece.chrome.y - piece.s : piece.chrome.y + piece.chrome.height; + return piece.chrome.bottomEdge ? piece.chrome.y + piece.chrome.height - piece.s : piece.chrome.y; + } + width: piece.s + height: piece.s + + Region { + intersection: Intersection.Subtract + radius: piece.s + width: piece.s * 2 + height: piece.s * 2 + x: piece.x - (piece.chrome.rightSide ? piece.s : 0) + y: piece.y - (piece.chrome.bottomEdge ? piece.s : 0) + } } } @@ -147,19 +355,54 @@ Item { Item { id: leftInputEnvelope - x: root.motionRunning ? Math.min(root.islandStartX, root.islandTargetX) - SettingsData.dankIslandSatelliteGap - leftInput.width : leftInput.x - y: leftInput.y - width: leftInput.width + root.leftEdgeSpread - height: leftInput.height + x: root.spanEdges ? 0 : (root.motionRunning ? Math.min(root.islandStartX, root.islandTargetX) - SettingsData.dankIslandSatelliteGap - leftInput.width : leftInput.x) + y: root.spanEdges ? root.chromeY : leftInput.y + width: root.spanEdges ? (leftInput.width > 0 ? Math.max(0, leftInput.x + leftInput.width + root.chromeInset) : 0) : leftInput.width + root.leftEdgeSpread + height: root.spanEdges ? (leftInput.width > 0 ? root.chromeHeight : 0) : leftInput.height } Item { id: rightInputEnvelope - x: root.motionRunning ? Math.min(root.islandStartRight, root.islandTargetRight) + SettingsData.dankIslandSatelliteGap : rightInput.x - y: rightInput.y - width: rightInput.width + root.rightEdgeSpread - height: rightInput.height + readonly property real edgeX: rightInput.width > 0 ? rightInput.x - root.chromeInset : root.width + + x: root.spanEdges ? edgeX : (root.motionRunning ? Math.min(root.islandStartRight, root.islandTargetRight) + SettingsData.dankIslandSatelliteGap : rightInput.x) + y: root.spanEdges ? root.chromeY : rightInput.y + width: root.spanEdges ? Math.max(0, root.width - edgeX) : rightInput.width + root.rightEdgeSpread + height: root.spanEdges ? (rightInput.width > 0 ? root.chromeHeight : 0) : rightInput.height + } + + IslandSatelliteChrome { + id: leftChrome + + x: 0 + y: root.chromeY + width: Math.max(0, leftInput.x + leftInput.width + root.chromePad) + height: root.chromeHeight + visible: root.backgroundEnabled && leftInput.width > 0 + fillColor: root.chromeColor + gothEnabled: root.gothCorners + sweep: root.sweepRadius + bottomEdge: root.bottomEdge + parentScreen: root.targetScreen + onVisibleChanged: blurRebuildTimer.restart() + } + + IslandSatelliteChrome { + id: rightChrome + + rightSide: true + x: rightInput.x - root.chromePad + y: root.chromeY + width: Math.max(0, root.width - x) + height: root.chromeHeight + visible: root.backgroundEnabled && rightInput.width > 0 + fillColor: root.chromeColor + gothEnabled: root.gothCorners + sweep: root.sweepRadius + bottomEdge: root.bottomEdge + parentScreen: root.targetScreen + onVisibleChanged: blurRebuildTimer.restart() } Item { @@ -185,6 +428,7 @@ Item { barSpacing: root.satelliteSpacing barConfig: root.satelliteConfig blurBarWindow: satelliteBarWindow + crossEdgeExtension: root.crossEdgeExtension } } @@ -211,6 +455,7 @@ Item { barSpacing: root.satelliteSpacing barConfig: root.satelliteConfig blurBarWindow: satelliteBarWindow + crossEdgeExtension: root.crossEdgeExtension } } } diff --git a/quickshell/Modules/Plugins/BasePill.qml b/quickshell/Modules/Plugins/BasePill.qml index c6cdba328..6c215efcf 100644 --- a/quickshell/Modules/Plugins/BasePill.qml +++ b/quickshell/Modules/Plugins/BasePill.qml @@ -27,6 +27,7 @@ Item { property bool isRightBarEdge: false property bool isTopBarEdge: false property bool isBottomBarEdge: false + property real crossEdgeExtension: 0 readonly property real dpr: parentScreen ? CompositorService.getScreenScale(parentScreen) : 1 readonly property real horizontalPadding: (barConfig?.removeWidgetPadding ?? false) ? 0 : Theme.snap((barConfig?.widgetPadding ?? 12) * (widgetThickness / 30), dpr) readonly property real visualWidth: Theme.snap(isVerticalOrientation ? widgetThickness : (contentLoader.item ? (contentLoader.item.implicitWidth + horizontalPadding * 2) : 0), dpr) @@ -36,8 +37,8 @@ Item { readonly property real gapExtension: sectionSpacing readonly property real leftMargin: !isVerticalOrientation ? (isLeftBarEdge && isFirst ? barEdgeExtension : (isFirst ? gapExtension : gapExtension / 2)) : 0 readonly property real rightMargin: !isVerticalOrientation ? (isRightBarEdge && isLast ? barEdgeExtension : (isLast ? gapExtension : gapExtension / 2)) : 0 - readonly property real topMargin: isVerticalOrientation ? (isTopBarEdge && isFirst ? barEdgeExtension : (isFirst ? gapExtension : gapExtension / 2)) : 0 - readonly property real bottomMargin: isVerticalOrientation ? (isBottomBarEdge && isLast ? barEdgeExtension : (isLast ? gapExtension : gapExtension / 2)) : 0 + readonly property real topMargin: isVerticalOrientation ? (isTopBarEdge && isFirst ? barEdgeExtension : (isFirst ? gapExtension : gapExtension / 2)) : (axis?.edge === "top" ? crossEdgeExtension : 0) + readonly property real bottomMargin: isVerticalOrientation ? (isBottomBarEdge && isLast ? barEdgeExtension : (isLast ? gapExtension : gapExtension / 2)) : (axis?.edge === "bottom" ? crossEdgeExtension : 0) readonly property bool barUsesOverlayLayer: LayerShell.envUsesOverlay("DMS_DANKBAR_LAYER", (barConfig?.useOverlayLayer ?? false) || CompositorService.framePeerSurfacesUseOverlayForScreen(parentScreen)) signal clicked diff --git a/quickshell/Modules/Settings/DankIslandTab.qml b/quickshell/Modules/Settings/DankIslandTab.qml index 736385bfb..f0a38ac8c 100644 --- a/quickshell/Modules/Settings/DankIslandTab.qml +++ b/quickshell/Modules/Settings/DankIslandTab.qml @@ -266,6 +266,19 @@ Item { } } + SettingsSliderRow { + settingKey: "dankIslandTransparency" + tags: ["island", "appearance", "surface", "opacity", "transparency", "blur"] + text: I18n.tr("Opacity", "island settings: island surface opacity slider") + unit: "%" + minimum: 0 + maximum: 100 + step: 1 + defaultValue: 100 + value: Math.round(SettingsData.dankIslandTransparency * 100) + onSliderValueChanged: value => SettingsData.set("dankIslandTransparency", value / 100) + } + SettingsToggleRow { settingKey: "dankIslandHighContrast" tags: ["island", "appearance", "contrast", "accessibility", "outline"] @@ -353,6 +366,54 @@ Item { onToggled: checked => SettingsData.set("dankIslandSatellitesEnabled", checked) } + SettingsToggleRow { + settingKey: "dankIslandSatelliteBackground" + tags: ["island", "satellite", "widgets", "background", "chrome"] + text: I18n.tr("Background", "island settings: satellite background toggle") + description: I18n.tr("Draw an island-styled background behind satellite widgets", "island settings: satellite background description") + checked: SettingsData.dankIslandSatelliteBackground + enabled: SettingsData.dankIslandSatellitesEnabled + onToggled: checked => SettingsData.set("dankIslandSatelliteBackground", checked) + } + + SettingsToggleRow { + settingKey: "dankIslandSatelliteGothCorners" + tags: ["island", "satellite", "goth", "corners", "wing", "sweep"] + text: I18n.tr("Goth Corners", "island settings: satellite goth corners toggle") + description: I18n.tr("Sweep the background into the screen edges", "island settings: satellite goth corners description") + checked: SettingsData.dankIslandSatelliteGothCorners + enabled: SettingsData.dankIslandSatellitesEnabled && SettingsData.dankIslandSatelliteBackground + onToggled: checked => SettingsData.set("dankIslandSatelliteGothCorners", checked) + } + + SettingsSliderRow { + settingKey: "dankIslandSatelliteSwoopRadius" + tags: ["island", "satellite", "goth", "corners", "radius", "sweep", "size"] + text: I18n.tr("Corner Radius", "island settings: satellite goth corner radius slider") + unit: "px" + minimum: 4 + maximum: 64 + step: 1 + defaultValue: 24 + value: SettingsData.dankIslandSatelliteSwoopRadius + enabled: SettingsData.dankIslandSatellitesEnabled && SettingsData.dankIslandSatelliteBackground && SettingsData.dankIslandSatelliteGothCorners + onSliderValueChanged: value => SettingsData.set("dankIslandSatelliteSwoopRadius", value) + } + + SettingsSliderRow { + settingKey: "dankIslandSatelliteTransparency" + tags: ["island", "satellite", "background", "opacity", "transparency", "blur"] + text: I18n.tr("Opacity", "island settings: satellite background opacity slider") + unit: "%" + minimum: 0 + maximum: 100 + step: 1 + defaultValue: 100 + value: Math.round(SettingsData.dankIslandSatelliteTransparency * 100) + enabled: SettingsData.dankIslandSatellitesEnabled && SettingsData.dankIslandSatelliteBackground + onSliderValueChanged: value => SettingsData.set("dankIslandSatelliteTransparency", value / 100) + } + SettingsButtonGroupRow { settingKey: "dankIslandSatellitePosition" tags: ["island", "satellite", "widgets", "position", "edges", "center"] diff --git a/quickshell/translations/settings_search_index.json b/quickshell/translations/settings_search_index.json index 1912a2012..ceaa35de4 100644 --- a/quickshell/translations/settings_search_index.json +++ b/quickshell/translations/settings_search_index.json @@ -12041,6 +12041,28 @@ "icon": "palette", "description": "Draw an outline and use the highest-contrast surface tone" }, + { + "section": "dankIslandSatelliteBackground", + "label": "Background", + "tabIndex": 46, + "category": "Dank Island", + "keywords": [ + "activities", + "background", + "behind", + "chrome", + "components", + "dank", + "draw", + "dynamic island", + "island", + "modules", + "satellite", + "styled", + "widgets" + ], + "description": "Draw an island-styled background behind satellite widgets" + }, { "section": "dankIslandHomeStatusSlot", "label": "Battery / Control Center", @@ -12168,6 +12190,27 @@ ], "description": "Resize the resting island to align with nearby widgets" }, + { + "section": "dankIslandSatelliteSwoopRadius", + "label": "Corner Radius", + "tabIndex": 46, + "category": "Dank Island", + "keywords": [ + "activities", + "corner", + "corners", + "dank", + "dynamic island", + "goth", + "island", + "radius", + "round", + "rounded", + "satellite", + "size", + "sweep" + ] + }, { "section": "dankIslandInstance", "label": "Dank Island - Beta", @@ -12259,6 +12302,30 @@ ], "description": "Floats above windows and other content" }, + { + "section": "dankIslandSatelliteGothCorners", + "label": "Goth Corners", + "tabIndex": 46, + "category": "Dank Island", + "keywords": [ + "activities", + "background", + "corners", + "dank", + "dynamic island", + "edges", + "goth", + "island", + "radius", + "round", + "rounded", + "satellite", + "screen", + "sweep", + "wing" + ], + "description": "Sweep the background into the screen edges" + }, { "section": "dankIslandHoverCloseDelay", "label": "Hide Delay", @@ -12523,6 +12590,40 @@ "icon": "notifications", "description": "Expand notifications by default instead of click or hover" }, + { + "section": "dankIslandSatelliteTransparency", + "label": "Opacity", + "tabIndex": 46, + "category": "Dank Island", + "keywords": [ + "activities", + "background", + "blur", + "dank", + "dynamic island", + "island", + "opacity", + "satellite", + "transparency" + ] + }, + { + "section": "dankIslandTransparency", + "label": "Opacity", + "tabIndex": 46, + "category": "Dank Island", + "keywords": [ + "activities", + "appearance", + "blur", + "dank", + "dynamic island", + "island", + "opacity", + "surface", + "transparency" + ] + }, { "section": "dankIslandHoverOpenDelay", "label": "Open Delay",