diff --git a/quickshell/Modules/DankBar/BarCanvas.qml b/quickshell/Modules/DankBar/BarCanvas.qml index 07a24930..b5e6880a 100644 --- a/quickshell/Modules/DankBar/BarCanvas.qml +++ b/quickshell/Modules/DankBar/BarCanvas.qml @@ -1,6 +1,6 @@ import QtQuick +import QtQuick.Shapes import qs.Common -import qs.Services Item { id: root @@ -19,12 +19,42 @@ Item { anchors.topMargin: -(gothEnabled && !axis.isVertical && axis.edge === "bottom" ? barWindow._wingR : 0) anchors.bottomMargin: -(gothEnabled && !axis.isVertical && axis.edge === "top" ? barWindow._wingR : 0) - readonly property real dpr: CompositorService.getScreenScale(barWindow.screen) + readonly property int barPos: barConfig?.position ?? 0 + readonly property bool isTop: barPos === SettingsData.Position.Top + readonly property bool isBottom: barPos === SettingsData.Position.Bottom + readonly property bool isLeft: barPos === SettingsData.Position.Left + readonly property bool isRight: barPos === SettingsData.Position.Right - function requestRepaint() { - debounceTimer.restart(); + readonly property real wing: gothEnabled ? barWindow._wingR : 0 + readonly property real rt: (barConfig?.squareCorners ?? false) ? 0 : Theme.cornerRadius + + property string _cachedMainPath: "" + property string _cachedBorderFullPath: "" + property string _cachedBorderEdgePath: "" + property string _pathKey: "" + + readonly property string currentPathKey: `${width}|${height}|${barPos}|${wing}|${rt}|${barBorder.inset}` + + onCurrentPathKeyChanged: { + if (_pathKey !== currentPathKey) { + _pathKey = currentPathKey; + _cachedMainPath = generatePathForPosition(); + _cachedBorderFullPath = generateBorderFullPath(); + _cachedBorderEdgePath = generateBorderEdgePath(); + } } + Component.onCompleted: { + _pathKey = currentPathKey; + _cachedMainPath = generatePathForPosition(); + _cachedBorderFullPath = generateBorderFullPath(); + _cachedBorderEdgePath = generateBorderEdgePath(); + } + + readonly property string mainPath: _cachedMainPath + readonly property string borderFullPath: _cachedBorderFullPath + readonly property string borderEdgePath: _cachedBorderEdgePath + MouseArea { anchors.fill: parent acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton @@ -44,398 +74,547 @@ Item { } } - Timer { - id: debounceTimer - interval: 50 - repeat: false - onTriggered: { - barShape.requestPaint(); - barTint.requestPaint(); - barBorder.requestPaint(); - } - } - - Canvas { + Shape { id: barShape anchors.fill: parent - antialiasing: true - renderTarget: Canvas.FramebufferObject - renderStrategy: Canvas.Cooperative + preferredRendererType: Shape.CurveRenderer - readonly property real correctWidth: Theme.px(root.width, dpr) - readonly property real correctHeight: Theme.px(root.height, dpr) - canvasSize: Qt.size(correctWidth, correctHeight) + ShapePath { + fillColor: barWindow._bgColor + strokeColor: "transparent" + strokeWidth: 0 - property real wing: (barConfig?.gothCornersEnabled ?? false) ? Theme.px(barWindow._wingR, dpr) : 0 - property real rt: (barConfig?.squareCorners ?? false) ? 0 : Theme.px(Theme.cornerRadius, dpr) - - onWingChanged: root.requestRepaint() - onRtChanged: root.requestRepaint() - onCorrectWidthChanged: root.requestRepaint() - onCorrectHeightChanged: root.requestRepaint() - onVisibleChanged: if (visible) - root.requestRepaint() - Component.onCompleted: root.requestRepaint() - - Connections { - target: root - function onDprChanged() { - root.requestRepaint(); + PathSvg { + path: root.mainPath } } - - Connections { - target: barWindow - function on_BgColorChanged() { - root.requestRepaint(); - } - function onGothCornersEnabledChanged() { - root.requestRepaint(); - } - function onWingtipsRadiusChanged() { - root.requestRepaint(); - } - } - - Connections { - target: Theme - 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; - - function drawTopPath() { - 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 { - 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.reset(); - ctx.clearRect(0, 0, W, H_raw); - - ctx.save(); - if (isBottom) { - ctx.translate(W, H_raw); - ctx.rotate(Math.PI); - } else if (isLeft) { - ctx.translate(0, W); - ctx.rotate(-Math.PI / 2); - } else if (isRight) { - ctx.translate(H_raw, 0); - ctx.rotate(Math.PI / 2); - } - - drawTopPath(); - ctx.restore(); - - ctx.fillStyle = barWindow._bgColor; - ctx.fill(); - } } - Canvas { + Shape { id: barTint anchors.fill: parent - antialiasing: true - renderTarget: Canvas.FramebufferObject - renderStrategy: Canvas.Cooperative + preferredRendererType: Shape.CurveRenderer - readonly property real correctWidth: Theme.px(root.width, dpr) - readonly property real correctHeight: Theme.px(root.height, dpr) - canvasSize: Qt.size(correctWidth, correctHeight) + readonly property real alphaTint: (barWindow._bgColor?.a ?? 1) < 0.99 ? (Theme.stateLayerOpacity ?? 0) : 0 - property real wing: (barConfig?.gothCornersEnabled ?? false) ? Theme.px(barWindow._wingR, dpr) : 0 - property real rt: (barConfig?.squareCorners ?? false) ? 0 : Theme.px(Theme.cornerRadius, dpr) - property real alphaTint: (barWindow._bgColor?.a ?? 1) < 0.99 ? (Theme.stateLayerOpacity ?? 0) : 0 + ShapePath { + fillColor: Qt.rgba(Theme.surface.r, Theme.surface.g, Theme.surface.b, barTint.alphaTint) + strokeColor: "transparent" + strokeWidth: 0 - onWingChanged: root.requestRepaint() - onRtChanged: root.requestRepaint() - onAlphaTintChanged: root.requestRepaint() - onCorrectWidthChanged: root.requestRepaint() - onCorrectHeightChanged: root.requestRepaint() - onVisibleChanged: if (visible) - root.requestRepaint() - Component.onCompleted: root.requestRepaint() - - Connections { - target: root - function onDprChanged() { - root.requestRepaint(); + PathSvg { + path: root.mainPath } } - - Connections { - target: barWindow - function on_BgColorChanged() { - root.requestRepaint(); - } - function onGothCornersEnabledChanged() { - root.requestRepaint(); - } - function onWingtipsRadiusChanged() { - root.requestRepaint(); - } - } - - Connections { - target: Theme - 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; - - function drawTopPath() { - 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 { - 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.reset(); - ctx.clearRect(0, 0, W, H_raw); - - ctx.save(); - if (isBottom) { - ctx.translate(W, H_raw); - ctx.rotate(Math.PI); - } else if (isLeft) { - ctx.translate(0, W); - ctx.rotate(-Math.PI / 2); - } else if (isRight) { - ctx.translate(H_raw, 0); - ctx.rotate(Math.PI / 2); - } - - drawTopPath(); - ctx.restore(); - - ctx.fillStyle = Qt.rgba(Theme.surface.r, Theme.surface.g, Theme.surface.b, alphaTint); - ctx.fill(); - } } - Canvas { + Shape { id: barBorder anchors.fill: parent visible: barConfig?.borderEnabled ?? false - renderTarget: Canvas.FramebufferObject - renderStrategy: Canvas.Cooperative + preferredRendererType: Shape.CurveRenderer - readonly property real correctWidth: Theme.px(root.width, dpr) - readonly property real correctHeight: Theme.px(root.height, dpr) - canvasSize: Qt.size(correctWidth, correctHeight) + readonly property real borderThickness: Math.max(1, barConfig?.borderThickness ?? 1) + readonly property real inset: 0.5 + readonly property string borderColorKey: barConfig?.borderColor || "surfaceText" + readonly property color baseColor: (borderColorKey === "surfaceText") ? Theme.surfaceText : (borderColorKey === "primary") ? Theme.primary : Theme.secondary + readonly property color borderColor: Theme.withAlpha(baseColor, barConfig?.borderOpacity ?? 1.0) + readonly property bool showFullBorder: (barConfig?.spacing ?? 4) > 0 - property real wing: (barConfig?.gothCornersEnabled ?? false) ? Theme.px(barWindow._wingR, dpr) : 0 - property real rt: (barConfig?.squareCorners ?? false) ? 0 : Theme.px(Theme.cornerRadius, dpr) - property bool borderEnabled: barConfig?.borderEnabled ?? false + ShapePath { + fillColor: "transparent" + strokeColor: barBorder.borderColor + strokeWidth: barBorder.borderThickness + joinStyle: ShapePath.RoundJoin + capStyle: ShapePath.FlatCap - antialiasing: rt > 0 || wing > 0 - - onWingChanged: root.requestRepaint() - onRtChanged: root.requestRepaint() - onBorderEnabledChanged: root.requestRepaint() - onCorrectWidthChanged: root.requestRepaint() - onCorrectHeightChanged: root.requestRepaint() - onVisibleChanged: if (visible) - root.requestRepaint() - Component.onCompleted: root.requestRepaint() - - Connections { - target: root - function onDprChanged() { - root.requestRepaint(); + PathSvg { + path: barBorder.showFullBorder ? root.borderFullPath : root.borderEdgePath } } - - Connections { - target: Theme - 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(); - } - } - - onPaint: { - 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 spacing = barConfig?.spacing ?? 4; - - ctx.reset(); - ctx.clearRect(0, 0, W, H_raw); - - ctx.save(); - if (isBottom) { - ctx.translate(W, H_raw); - ctx.rotate(Math.PI); - } else if (isLeft) { - ctx.translate(0, W); - ctx.rotate(-Math.PI / 2); - } else if (isRight) { - 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 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.strokeStyle = color; - ctx.lineWidth = devThickness * 2; - ctx.lineJoin = "round"; - ctx.lineCap = "butt"; - - 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 { - 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(); - } - - drawFullShape(); - ctx.clip(); - - 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(); - - ctx.restore(); - } + } + + function generatePathForPosition() { + if (isTop) + return generateTopPath(); + if (isBottom) + return generateBottomPath(); + if (isLeft) + return generateLeftPath(); + if (isRight) + return generateRightPath(); + return generateTopPath(); + } + + function generateBorderPathForPosition() { + if (isTop) + return generateTopBorderPath(); + if (isBottom) + return generateBottomBorderPath(); + if (isLeft) + return generateLeftBorderPath(); + if (isRight) + return generateRightBorderPath(); + return generateTopBorderPath(); + } + + function generateTopPath() { + const w = width; + const h = height - wing; + const r = wing; + const cr = rt; + + if (w <= 0 || h <= 0) + return ""; + + let d = `M ${cr} 0`; + d += ` L ${w - cr} 0`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${w} ${cr}`; + if (r > 0) { + d += ` L ${w} ${h + r}`; + d += ` A ${r} ${r} 0 0 0 ${w - r} ${h}`; + d += ` L ${r} ${h}`; + d += ` A ${r} ${r} 0 0 0 0 ${h + r}`; + } else { + d += ` L ${w} ${h - cr}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${w - cr} ${h}`; + d += ` L ${cr} ${h}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 0 ${h - cr}`; + } + d += ` L 0 ${cr}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${cr} 0`; + d += " Z"; + return d; + } + + function generateBottomPath() { + const w = width; + const h = height - wing; + const r = wing; + const cr = rt; + + if (w <= 0 || h <= 0) + return ""; + + let d = `M ${cr} ${height}`; + d += ` L ${w - cr} ${height}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 0 ${w} ${height - cr}`; + if (r > 0) { + d += ` L ${w} 0`; + d += ` A ${r} ${r} 0 0 1 ${w - r} ${r}`; + d += ` L ${r} ${r}`; + d += ` A ${r} ${r} 0 0 1 0 0`; + } else { + d += ` L ${w} ${cr}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 0 ${w - cr} 0`; + d += ` L ${cr} 0`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 0 0 ${cr}`; + } + d += ` L 0 ${height - cr}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 0 ${cr} ${height}`; + d += " Z"; + return d; + } + + function generateLeftPath() { + const w = width - wing; + const h = height; + const r = wing; + const cr = rt; + + if (w <= 0 || h <= 0) + return ""; + + let d = `M 0 ${cr}`; + d += ` L 0 ${h - cr}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 0 ${cr} ${h}`; + if (r > 0) { + d += ` L ${w + r} ${h}`; + d += ` A ${r} ${r} 0 0 1 ${w} ${h - r}`; + d += ` L ${w} ${r}`; + d += ` A ${r} ${r} 0 0 1 ${w + r} 0`; + } else { + d += ` L ${w - cr} ${h}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 0 ${w} ${h - cr}`; + d += ` L ${w} ${cr}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 0 ${w - cr} 0`; + } + d += ` L ${cr} 0`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 0 0 ${cr}`; + d += " Z"; + return d; + } + + function generateRightPath() { + const w = width - wing; + const h = height; + const r = wing; + const cr = rt; + + if (w <= 0 || h <= 0) + return ""; + + let d = `M ${width} ${cr}`; + d += ` L ${width} ${h - cr}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${width - cr} ${h}`; + if (r > 0) { + d += ` L 0 ${h}`; + d += ` A ${r} ${r} 0 0 0 ${r} ${h - r}`; + d += ` L ${r} ${r}`; + d += ` A ${r} ${r} 0 0 0 0 0`; + } else { + d += ` L ${cr} ${h}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 0 ${h - cr}`; + d += ` L 0 ${cr}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${cr} 0`; + } + d += ` L ${width - cr} 0`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${width} ${cr}`; + d += " Z"; + return d; + } + + function generateTopBorderPath() { + const w = barBorder.width; + const h = barBorder.height - wing; + const r = wing; + const cr = rt; + + if (w <= 0 || h <= 0) + return ""; + + let d = ""; + if (r > 0) { + d = `M ${w} ${h + r}`; + d += ` A ${r} ${r} 0 0 0 ${w - r} ${h}`; + d += ` L ${r} ${h}`; + d += ` A ${r} ${r} 0 0 0 0 ${h + r}`; + } else { + d = `M ${w} ${h - cr}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${w - cr} ${h}`; + d += ` L ${cr} ${h}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 0 ${h - cr}`; + } + return d; + } + + function generateBottomBorderPath() { + const w = barBorder.width; + const r = wing; + const cr = rt; + + if (w <= 0) + return ""; + + let d = ""; + if (r > 0) { + d = `M ${w} 0`; + d += ` A ${r} ${r} 0 0 1 ${w - r} ${r}`; + d += ` L ${r} ${r}`; + d += ` A ${r} ${r} 0 0 1 0 0`; + } else { + d = `M ${w} ${cr}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${w - cr} 0`; + d += ` L ${cr} 0`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 0 ${cr}`; + } + return d; + } + + function generateLeftBorderPath() { + const w = barBorder.width - wing; + const h = barBorder.height; + const r = wing; + const cr = rt; + + if (h <= 0) + return ""; + + let d = ""; + if (r > 0) { + d = `M ${w + r} ${h}`; + d += ` A ${r} ${r} 0 0 1 ${w} ${h - r}`; + d += ` L ${w} ${r}`; + d += ` A ${r} ${r} 0 0 1 ${w + r} 0`; + } else { + d = `M ${w - cr} ${h}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${w} ${h - cr}`; + d += ` L ${w} ${cr}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${w - cr} 0`; + } + return d; + } + + function generateRightBorderPath() { + const h = barBorder.height; + const r = wing; + const cr = rt; + + if (h <= 0) + return ""; + + let d = ""; + if (r > 0) { + d = `M 0 ${h}`; + d += ` A ${r} ${r} 0 0 0 ${r} ${h - r}`; + d += ` L ${r} ${r}`; + d += ` A ${r} ${r} 0 0 0 0 0`; + } else { + d = `M ${cr} ${h}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 0 ${h - cr}`; + d += ` L 0 ${cr}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${cr} 0`; + } + return d; + } + + function generateBorderFullPath() { + const i = barBorder.inset; + const r = wing; + const cr = rt; + + if (isTop) { + const w = width - i * 2; + const h = height - wing - i * 2; + if (w <= 0 || h <= 0) + return ""; + + let d = `M ${i + cr} ${i}`; + d += ` L ${i + w - cr} ${i}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${i + w} ${i + cr}`; + if (r > 0) { + d += ` L ${i + w} ${height - i}`; + d += ` A ${r} ${r} 0 0 0 ${i + w - r} ${i + h}`; + d += ` L ${i + r} ${i + h}`; + d += ` A ${r} ${r} 0 0 0 ${i} ${height - i}`; + } else { + d += ` L ${i + w} ${i + h - cr}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${i + w - cr} ${i + h}`; + d += ` L ${i + cr} ${i + h}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${i} ${i + h - cr}`; + } + d += ` L ${i} ${i + cr}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${i + cr} ${i}`; + d += " Z"; + return d; + } + + if (isBottom) { + const w = width - i * 2; + const h = height - wing - i * 2; + if (w <= 0 || h <= 0) + return ""; + + let d = `M ${i + cr} ${height - i}`; + d += ` L ${i + w - cr} ${height - i}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 0 ${i + w} ${height - i - cr}`; + if (r > 0) { + d += ` L ${i + w} ${i}`; + d += ` A ${r} ${r} 0 0 1 ${i + w - r} ${i + r}`; + d += ` L ${i + r} ${i + r}`; + d += ` A ${r} ${r} 0 0 1 ${i} ${i}`; + } else { + d += ` L ${i + w} ${i + cr}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 0 ${i + w - cr} ${i}`; + d += ` L ${i + cr} ${i}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 0 ${i} ${i + cr}`; + } + d += ` L ${i} ${height - i - cr}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 0 ${i + cr} ${height - i}`; + d += " Z"; + return d; + } + + if (isLeft) { + const w = width - wing - i * 2; + const h = height - i * 2; + if (w <= 0 || h <= 0) + return ""; + + let d = `M ${i} ${i + cr}`; + d += ` L ${i} ${i + h - cr}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 0 ${i + cr} ${i + h}`; + if (r > 0) { + d += ` L ${width - i} ${i + h}`; + d += ` A ${r} ${r} 0 0 1 ${i + w} ${i + h - r}`; + d += ` L ${i + w} ${i + r}`; + d += ` A ${r} ${r} 0 0 1 ${width - i} ${i}`; + } else { + d += ` L ${i + w - cr} ${i + h}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 0 ${i + w} ${i + h - cr}`; + d += ` L ${i + w} ${i + cr}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 0 ${i + w - cr} ${i}`; + } + d += ` L ${i + cr} ${i}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 0 ${i} ${i + cr}`; + d += " Z"; + return d; + } + + if (isRight) { + const w = width - wing - i * 2; + const h = height - i * 2; + if (w <= 0 || h <= 0) + return ""; + + let d = `M ${width - i} ${i + cr}`; + d += ` L ${width - i} ${i + h - cr}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${width - i - cr} ${i + h}`; + if (r > 0) { + d += ` L ${i} ${i + h}`; + d += ` A ${r} ${r} 0 0 0 ${i + r} ${i + h - r}`; + d += ` L ${i + r} ${i + r}`; + d += ` A ${r} ${r} 0 0 0 ${i} ${i}`; + } else { + d += ` L ${wing + i + cr} ${i + h}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${wing + i} ${i + h - cr}`; + d += ` L ${wing + i} ${i + cr}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${wing + i + cr} ${i}`; + } + d += ` L ${width - i - cr} ${i}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${width - i} ${i + cr}`; + d += " Z"; + return d; + } + + return ""; + } + + function generateBorderEdgePath() { + const i = barBorder.inset; + const r = wing; + const cr = rt; + + if (isTop) { + const w = width - i * 2; + const h = height - wing - i * 2; + if (w <= 0 || h <= 0) + return ""; + + let d = ""; + if (r > 0) { + d = `M ${i + w} ${i + h + r}`; + d += ` A ${r} ${r} 0 0 0 ${i + w - r} ${i + h}`; + d += ` L ${i + r} ${i + h}`; + d += ` A ${r} ${r} 0 0 0 ${i} ${i + h + r}`; + } else { + d = `M ${i + w} ${i + h - cr}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${i + w - cr} ${i + h}`; + d += ` L ${i + cr} ${i + h}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${i} ${i + h - cr}`; + } + return d; + } + + if (isBottom) { + const w = width - i * 2; + if (w <= 0) + return ""; + + let d = ""; + if (r > 0) { + d = `M ${i + w} ${i}`; + d += ` A ${r} ${r} 0 0 1 ${i + w - r} ${i + r}`; + d += ` L ${i + r} ${i + r}`; + d += ` A ${r} ${r} 0 0 1 ${i} ${i}`; + } else { + d = `M ${i + w} ${i + cr}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${i + w - cr} ${i}`; + d += ` L ${i + cr} ${i}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${i} ${i + cr}`; + } + return d; + } + + if (isLeft) { + const w = width - wing - i * 2; + const h = height - i * 2; + if (h <= 0) + return ""; + + let d = ""; + if (r > 0) { + d = `M ${i + w + r} ${i + h}`; + d += ` A ${r} ${r} 0 0 1 ${i + w} ${i + h - r}`; + d += ` L ${i + w} ${i + r}`; + d += ` A ${r} ${r} 0 0 1 ${i + w + r} ${i}`; + } else { + d = `M ${i + w - cr} ${i + h}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${i + w} ${i + h - cr}`; + d += ` L ${i + w} ${i + cr}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${i + w - cr} ${i}`; + } + return d; + } + + if (isRight) { + const h = height - i * 2; + if (h <= 0) + return ""; + + let d = ""; + if (r > 0) { + d = `M ${i} ${i + h}`; + d += ` A ${r} ${r} 0 0 0 ${i + r} ${i + h - r}`; + d += ` L ${i + r} ${i + r}`; + d += ` A ${r} ${r} 0 0 0 ${i} ${i}`; + } else { + d = `M ${i + cr} ${i + h}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${i} ${i + h - cr}`; + d += ` L ${i} ${i + cr}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${i + cr} ${i}`; + } + return d; + } + + return ""; } }