From 5e77a10a815e66db59db3d6e8894c7b9ef5fe5e7 Mon Sep 17 00:00:00 2001 From: bbedward Date: Sun, 23 Nov 2025 23:55:07 -0500 Subject: [PATCH] dankbar: make border shape respect goth radius part of #804 --- quickshell/Modules/DankBar/BarCanvas.qml | 437 ++++++++++++----------- 1 file changed, 229 insertions(+), 208 deletions(-) diff --git a/quickshell/Modules/DankBar/BarCanvas.qml b/quickshell/Modules/DankBar/BarCanvas.qml index a5ef3e19..07a24930 100644 --- a/quickshell/Modules/DankBar/BarCanvas.qml +++ b/quickshell/Modules/DankBar/BarCanvas.qml @@ -1,5 +1,4 @@ import QtQuick -import Quickshell.Hyprland import qs.Common import qs.Services @@ -23,7 +22,7 @@ Item { readonly property real dpr: CompositorService.getScreenScale(barWindow.screen) function requestRepaint() { - debounceTimer.restart() + debounceTimer.restart(); } MouseArea { @@ -31,17 +30,17 @@ Item { acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton z: -999 onClicked: { - const activePopout = PopoutManager.getActivePopout(barWindow.screen) + const activePopout = PopoutManager.getActivePopout(barWindow.screen); if (activePopout) { if (activePopout.dashVisible !== undefined) { - activePopout.dashVisible = false + activePopout.dashVisible = false; } else if (activePopout.notificationHistoryVisible !== undefined) { - activePopout.notificationHistoryVisible = false + activePopout.notificationHistoryVisible = false; } else { - activePopout.close() + activePopout.close(); } } - TrayMenuManager.closeAllMenus() + TrayMenuManager.closeAllMenus(); } } @@ -50,9 +49,9 @@ Item { interval: 50 repeat: false onTriggered: { - barShape.requestPaint() - barTint.requestPaint() - barBorder.requestPaint() + barShape.requestPaint(); + barTint.requestPaint(); + barBorder.requestPaint(); } } @@ -74,85 +73,98 @@ Item { onRtChanged: root.requestRepaint() onCorrectWidthChanged: root.requestRepaint() onCorrectHeightChanged: root.requestRepaint() - onVisibleChanged: if (visible) root.requestRepaint() + onVisibleChanged: if (visible) + root.requestRepaint() Component.onCompleted: root.requestRepaint() Connections { target: root - function onDprChanged() { root.requestRepaint() } + function onDprChanged() { + root.requestRepaint(); + } } Connections { target: barWindow - function on_BgColorChanged() { root.requestRepaint() } - function onGothCornersEnabledChanged() { root.requestRepaint() } - function onWingtipsRadiusChanged() { root.requestRepaint() } + function on_BgColorChanged() { + root.requestRepaint(); + } + function onGothCornersEnabledChanged() { + root.requestRepaint(); + } + function onWingtipsRadiusChanged() { + root.requestRepaint(); + } } Connections { target: Theme - function onIsLightModeChanged() { root.requestRepaint() } - function onSurfaceContainerChanged() { root.requestRepaint() } + function onIsLightModeChanged() { + root.requestRepaint(); + } + function onSurfaceContainerChanged() { + root.requestRepaint(); + } } onPaint: { - const ctx = getContext("2d") - const W = barWindow.isVertical ? correctHeight : correctWidth - const H_raw = barWindow.isVertical ? correctWidth : correctHeight - const R = wing - const RT = rt - const H = H_raw - (R > 0 ? R : 0) - const barPos = barConfig?.position ?? 0 - const isTop = barPos === SettingsData.Position.Top - const isBottom = barPos === SettingsData.Position.Bottom - const isLeft = barPos === SettingsData.Position.Left - const isRight = barPos === SettingsData.Position.Right + const ctx = getContext("2d"); + const W = barWindow.isVertical ? correctHeight : correctWidth; + const H_raw = barWindow.isVertical ? correctWidth : correctHeight; + const R = wing; + const RT = rt; + const H = H_raw - (R > 0 ? R : 0); + const barPos = barConfig?.position ?? 0; + const isTop = barPos === SettingsData.Position.Top; + const isBottom = barPos === SettingsData.Position.Bottom; + const isLeft = barPos === SettingsData.Position.Left; + const isRight = barPos === SettingsData.Position.Right; function drawTopPath() { - ctx.beginPath() - ctx.moveTo(RT, 0) - ctx.lineTo(W - RT, 0) - ctx.arcTo(W, 0, W, RT, RT) - ctx.lineTo(W, H) + ctx.beginPath(); + ctx.moveTo(RT, 0); + ctx.lineTo(W - RT, 0); + ctx.arcTo(W, 0, W, RT, RT); + ctx.lineTo(W, H); if (R > 0) { - ctx.lineTo(W, H + R) - ctx.arc(W - R, H + R, R, 0, -Math.PI / 2, true) - ctx.lineTo(R, H) - ctx.arc(R, H + R, R, -Math.PI / 2, -Math.PI, true) - ctx.lineTo(0, H + R) + ctx.lineTo(W, H + R); + ctx.arc(W - R, H + R, R, 0, -Math.PI / 2, true); + ctx.lineTo(R, H); + ctx.arc(R, H + R, R, -Math.PI / 2, -Math.PI, true); + ctx.lineTo(0, H + R); } else { - ctx.lineTo(W, H - RT) - ctx.arcTo(W, H, W - RT, H, RT) - ctx.lineTo(RT, H) - ctx.arcTo(0, H, 0, H - RT, RT) + ctx.lineTo(W, H - RT); + ctx.arcTo(W, H, W - RT, H, RT); + ctx.lineTo(RT, H); + ctx.arcTo(0, H, 0, H - RT, RT); } - ctx.lineTo(0, RT) - ctx.arcTo(0, 0, RT, 0, RT) - ctx.closePath() + ctx.lineTo(0, RT); + ctx.arcTo(0, 0, RT, 0, RT); + ctx.closePath(); } - ctx.reset() - ctx.clearRect(0, 0, W, H_raw) + ctx.reset(); + ctx.clearRect(0, 0, W, H_raw); - ctx.save() + ctx.save(); if (isBottom) { - ctx.translate(W, H_raw) - ctx.rotate(Math.PI) + ctx.translate(W, H_raw); + ctx.rotate(Math.PI); } else if (isLeft) { - ctx.translate(0, W) - ctx.rotate(-Math.PI / 2) + ctx.translate(0, W); + ctx.rotate(-Math.PI / 2); } else if (isRight) { - ctx.translate(H_raw, 0) - ctx.rotate(Math.PI / 2) + ctx.translate(H_raw, 0); + ctx.rotate(Math.PI / 2); } - drawTopPath() - ctx.restore() + drawTopPath(); + ctx.restore(); - ctx.fillStyle = barWindow._bgColor - ctx.fill() + ctx.fillStyle = barWindow._bgColor; + ctx.fill(); } } @@ -176,85 +188,98 @@ Item { onAlphaTintChanged: root.requestRepaint() onCorrectWidthChanged: root.requestRepaint() onCorrectHeightChanged: root.requestRepaint() - onVisibleChanged: if (visible) root.requestRepaint() + onVisibleChanged: if (visible) + root.requestRepaint() Component.onCompleted: root.requestRepaint() Connections { target: root - function onDprChanged() { root.requestRepaint() } + function onDprChanged() { + root.requestRepaint(); + } } Connections { target: barWindow - function on_BgColorChanged() { root.requestRepaint() } - function onGothCornersEnabledChanged() { root.requestRepaint() } - function onWingtipsRadiusChanged() { root.requestRepaint() } + function on_BgColorChanged() { + root.requestRepaint(); + } + function onGothCornersEnabledChanged() { + root.requestRepaint(); + } + function onWingtipsRadiusChanged() { + root.requestRepaint(); + } } Connections { target: Theme - function onIsLightModeChanged() { root.requestRepaint() } - function onSurfaceChanged() { root.requestRepaint() } + function onIsLightModeChanged() { + root.requestRepaint(); + } + function onSurfaceChanged() { + root.requestRepaint(); + } } onPaint: { - const ctx = getContext("2d") - const W = barWindow.isVertical ? correctHeight : correctWidth - const H_raw = barWindow.isVertical ? correctWidth : correctHeight - const R = wing - const RT = rt - const H = H_raw - (R > 0 ? R : 0) - const barPos = barConfig?.position ?? 0 - const isTop = barPos === SettingsData.Position.Top - const isBottom = barPos === SettingsData.Position.Bottom - const isLeft = barPos === SettingsData.Position.Left - const isRight = barPos === SettingsData.Position.Right + const ctx = getContext("2d"); + const W = barWindow.isVertical ? correctHeight : correctWidth; + const H_raw = barWindow.isVertical ? correctWidth : correctHeight; + const R = wing; + const RT = rt; + const H = H_raw - (R > 0 ? R : 0); + const barPos = barConfig?.position ?? 0; + const isTop = barPos === SettingsData.Position.Top; + const isBottom = barPos === SettingsData.Position.Bottom; + const isLeft = barPos === SettingsData.Position.Left; + const isRight = barPos === SettingsData.Position.Right; function drawTopPath() { - ctx.beginPath() - ctx.moveTo(RT, 0) - ctx.lineTo(W - RT, 0) - ctx.arcTo(W, 0, W, RT, RT) - ctx.lineTo(W, H) + ctx.beginPath(); + ctx.moveTo(RT, 0); + ctx.lineTo(W - RT, 0); + ctx.arcTo(W, 0, W, RT, RT); + ctx.lineTo(W, H); if (R > 0) { - ctx.lineTo(W, H + R) - ctx.arc(W - R, H + R, R, 0, -Math.PI / 2, true) - ctx.lineTo(R, H) - ctx.arc(R, H + R, R, -Math.PI / 2, -Math.PI, true) - ctx.lineTo(0, H + R) + ctx.lineTo(W, H + R); + ctx.arc(W - R, H + R, R, 0, -Math.PI / 2, true); + ctx.lineTo(R, H); + ctx.arc(R, H + R, R, -Math.PI / 2, -Math.PI, true); + ctx.lineTo(0, H + R); } else { - ctx.lineTo(W, H - RT) - ctx.arcTo(W, H, W - RT, H, RT) - ctx.lineTo(RT, H) - ctx.arcTo(0, H, 0, H - RT, RT) + ctx.lineTo(W, H - RT); + ctx.arcTo(W, H, W - RT, H, RT); + ctx.lineTo(RT, H); + ctx.arcTo(0, H, 0, H - RT, RT); } - ctx.lineTo(0, RT) - ctx.arcTo(0, 0, RT, 0, RT) - ctx.closePath() + ctx.lineTo(0, RT); + ctx.arcTo(0, 0, RT, 0, RT); + ctx.closePath(); } - ctx.reset() - ctx.clearRect(0, 0, W, H_raw) + ctx.reset(); + ctx.clearRect(0, 0, W, H_raw); - ctx.save() + ctx.save(); if (isBottom) { - ctx.translate(W, H_raw) - ctx.rotate(Math.PI) + ctx.translate(W, H_raw); + ctx.rotate(Math.PI); } else if (isLeft) { - ctx.translate(0, W) - ctx.rotate(-Math.PI / 2) + ctx.translate(0, W); + ctx.rotate(-Math.PI / 2); } else if (isRight) { - ctx.translate(H_raw, 0) - ctx.rotate(Math.PI / 2) + ctx.translate(H_raw, 0); + ctx.rotate(Math.PI / 2); } - drawTopPath() - ctx.restore() + drawTopPath(); + ctx.restore(); - ctx.fillStyle = Qt.rgba(Theme.surface.r, Theme.surface.g, Theme.surface.b, alphaTint) - ctx.fill() + ctx.fillStyle = Qt.rgba(Theme.surface.r, Theme.surface.g, Theme.surface.b, alphaTint); + ctx.fill(); } } @@ -280,141 +305,137 @@ Item { onBorderEnabledChanged: root.requestRepaint() onCorrectWidthChanged: root.requestRepaint() onCorrectHeightChanged: root.requestRepaint() - onVisibleChanged: if (visible) root.requestRepaint() + onVisibleChanged: if (visible) + root.requestRepaint() Component.onCompleted: root.requestRepaint() Connections { target: root - function onDprChanged() { root.requestRepaint() } + function onDprChanged() { + root.requestRepaint(); + } } Connections { target: Theme - function onIsLightModeChanged() { root.requestRepaint() } - function onSurfaceTextChanged() { root.requestRepaint() } - function onPrimaryChanged() { root.requestRepaint() } - function onSecondaryChanged() { root.requestRepaint() } - function onOutlineChanged() { root.requestRepaint() } + function onIsLightModeChanged() { + root.requestRepaint(); + } + function onSurfaceTextChanged() { + root.requestRepaint(); + } + function onPrimaryChanged() { + root.requestRepaint(); + } + function onSecondaryChanged() { + root.requestRepaint(); + } + function onOutlineChanged() { + root.requestRepaint(); + } } Connections { target: barWindow - function onGothCornersEnabledChanged() { root.requestRepaint() } - function onWingtipsRadiusChanged() { root.requestRepaint() } + function onGothCornersEnabledChanged() { + root.requestRepaint(); + } + function onWingtipsRadiusChanged() { + root.requestRepaint(); + } } onPaint: { - if (!borderEnabled) return + if (!borderEnabled) + return; + const ctx = getContext("2d"); + const W = barWindow.isVertical ? correctHeight : correctWidth; + const H_raw = barWindow.isVertical ? correctWidth : correctHeight; + const R = wing; + const RT = rt; + const H = H_raw - (R > 0 ? R : 0); + const barPos = barConfig?.position ?? 0; + const isTop = barPos === SettingsData.Position.Top; + const isBottom = barPos === SettingsData.Position.Bottom; + const isLeft = barPos === SettingsData.Position.Left; + const isRight = barPos === SettingsData.Position.Right; - const ctx = getContext("2d") - const W = barWindow.isVertical ? correctHeight : correctWidth - const H_raw = barWindow.isVertical ? correctWidth : correctHeight - const R = wing - const RT = rt - const H = H_raw - (R > 0 ? R : 0) - const barPos = barConfig?.position ?? 0 - const isTop = barPos === SettingsData.Position.Top - const isBottom = barPos === SettingsData.Position.Bottom - const isLeft = barPos === SettingsData.Position.Left - const isRight = barPos === SettingsData.Position.Right + const spacing = barConfig?.spacing ?? 4; - const spacing = barConfig?.spacing ?? 4 - const hasEdgeGap = spacing > 0 || RT > 0 + ctx.reset(); + ctx.clearRect(0, 0, W, H_raw); - ctx.reset() - ctx.clearRect(0, 0, W, H_raw) - - ctx.save() + ctx.save(); if (isBottom) { - ctx.translate(W, H_raw) - ctx.rotate(Math.PI) + ctx.translate(W, H_raw); + ctx.rotate(Math.PI); } else if (isLeft) { - ctx.translate(0, W) - ctx.rotate(-Math.PI / 2) + ctx.translate(0, W); + ctx.rotate(-Math.PI / 2); } else if (isRight) { - ctx.translate(H_raw, 0) - ctx.rotate(Math.PI / 2) + ctx.translate(H_raw, 0); + ctx.rotate(Math.PI / 2); } - const uiThickness = Math.max(1, barConfig?.borderThickness ?? 1) - const devThickness = Math.max(1, Math.round(Theme.px(uiThickness, dpr))) + const uiThickness = Math.max(1, barConfig?.borderThickness ?? 1); + const devThickness = Math.max(1, Math.round(Theme.px(uiThickness, dpr))); - const key = barConfig?.borderColor || "surfaceText" - const base = (key === "surfaceText") ? Theme.surfaceText - : (key === "primary") ? Theme.primary - : Theme.secondary - const color = Theme.withAlpha(base, barConfig?.borderOpacity ?? 1.0) + const key = barConfig?.borderColor || "surfaceText"; + const base = (key === "surfaceText") ? Theme.surfaceText : (key === "primary") ? Theme.primary : Theme.secondary; + const color = Theme.withAlpha(base, barConfig?.borderOpacity ?? 1.0); - ctx.globalCompositeOperation = "source-over" - ctx.fillStyle = color + ctx.strokeStyle = color; + ctx.lineWidth = devThickness * 2; + ctx.lineJoin = "round"; + ctx.lineCap = "butt"; - function drawTopBorder() { - if (!hasEdgeGap) { - ctx.beginPath() - ctx.rect(0, H - devThickness, W, devThickness) - ctx.fill() + function drawFullShape() { + ctx.beginPath(); + ctx.moveTo(RT, 0); + ctx.lineTo(W - RT, 0); + ctx.arcTo(W, 0, W, RT, RT); + ctx.lineTo(W, H); + + if (R > 0) { + ctx.lineTo(W, H + R); + ctx.arc(W - R, H + R, R, 0, -Math.PI / 2, true); + ctx.lineTo(R, H); + ctx.arc(R, H + R, R, -Math.PI / 2, -Math.PI, true); + ctx.lineTo(0, H + R); } else { - const thk = devThickness - const RTi = Math.max(0, RT - thk) - const Ri = Math.max(0, R - thk) + ctx.lineTo(W, H - RT); + ctx.arcTo(W, H, W - RT, H, RT); + ctx.lineTo(RT, H); + ctx.arcTo(0, H, 0, H - RT, RT); + } - ctx.beginPath() + ctx.lineTo(0, RT); + ctx.arcTo(0, 0, RT, 0, RT); + ctx.closePath(); + } - if (R > 0 && Ri > 0) { - ctx.moveTo(RT, 0) - ctx.lineTo(W - RT, 0) - ctx.arcTo(W, 0, W, RT, RT) - ctx.lineTo(W, H) - ctx.lineTo(W, H + R) - ctx.arc(W - R, H + R, R, 0, -Math.PI / 2, true) - ctx.lineTo(R, H) - ctx.arc(R, H + R, R, -Math.PI / 2, -Math.PI, true) - ctx.lineTo(0, H + R) - ctx.lineTo(0, RT) - ctx.arcTo(0, 0, RT, 0, RT) - ctx.closePath() + drawFullShape(); + ctx.clip(); - ctx.moveTo(RT, thk) - ctx.arcTo(thk, thk, thk, RT, RTi) - ctx.lineTo(thk, H + R) - ctx.arc(R, H + R, Ri, -Math.PI, -Math.PI / 2, false) - ctx.lineTo(W - R, H + thk) - ctx.arc(W - R, H + R, Ri, -Math.PI / 2, 0, false) - ctx.lineTo(W - thk, H + R) - ctx.lineTo(W - thk, RT) - ctx.arcTo(W - thk, thk, W - RT, thk, RTi) - ctx.lineTo(RT, thk) - ctx.closePath() - } else { - ctx.moveTo(RT, 0) - ctx.lineTo(W - RT, 0) - ctx.arcTo(W, 0, W, RT, RT) - ctx.lineTo(W, H - RT) - ctx.arcTo(W, H, W - RT, H, RT) - ctx.lineTo(RT, H) - ctx.arcTo(0, H, 0, H - RT, RT) - ctx.lineTo(0, RT) - ctx.arcTo(0, 0, RT, 0, RT) - ctx.closePath() - - ctx.moveTo(RT, thk) - ctx.arcTo(thk, thk, thk, RT, RTi) - ctx.lineTo(thk, H - RT) - ctx.arcTo(thk, H - thk, RT, H - thk, RTi) - ctx.lineTo(W - RT, H - thk) - ctx.arcTo(W - thk, H - thk, W - thk, H - RT, RTi) - ctx.lineTo(W - thk, RT) - ctx.arcTo(W - thk, thk, W - RT, thk, RTi) - ctx.lineTo(RT, thk) - ctx.closePath() - } - - ctx.fill("evenodd") + if (spacing > 0) { + drawFullShape(); + } else { + ctx.beginPath(); + if (R > 0) { + ctx.moveTo(W, H + R); + ctx.arc(W - R, H + R, R, 0, -Math.PI / 2, true); + ctx.lineTo(R, H); + ctx.arc(R, H + R, R, -Math.PI / 2, -Math.PI, true); + } else { + ctx.moveTo(W, H - RT); + ctx.arcTo(W, H, W - RT, H, RT); + ctx.lineTo(RT, H); + ctx.arcTo(0, H, 0, H - RT, RT); } } + ctx.stroke(); - drawTopBorder() - ctx.restore() + ctx.restore(); } } }