From 3462bcc46ecf74f576ea4397f16492c16bd75b10 Mon Sep 17 00:00:00 2001 From: Nippy Date: Fri, 8 May 2026 19:50:49 +0200 Subject: raveos update --- .../theme-data/dms/Modules/DankBar/BarCanvas.qml | 671 +++++++++++++++++++++ 1 file changed, 671 insertions(+) create mode 100644 raveos-hyprland-theme/theme-data/dms/Modules/DankBar/BarCanvas.qml (limited to 'raveos-hyprland-theme/theme-data/dms/Modules/DankBar/BarCanvas.qml') diff --git a/raveos-hyprland-theme/theme-data/dms/Modules/DankBar/BarCanvas.qml b/raveos-hyprland-theme/theme-data/dms/Modules/DankBar/BarCanvas.qml new file mode 100644 index 0000000..df3f17f --- /dev/null +++ b/raveos-hyprland-theme/theme-data/dms/Modules/DankBar/BarCanvas.qml @@ -0,0 +1,671 @@ +import QtQuick +import QtQuick.Shapes +import qs.Common +import qs.Services + +Item { + id: root + + required property var barWindow + required property var axis + required property var barConfig + + anchors.fill: parent + + anchors.left: parent.left + anchors.top: parent.top + readonly property bool gothEnabled: (barConfig?.gothCornersEnabled ?? false) && !barWindow.hasMaximizedToplevel + anchors.leftMargin: -(gothEnabled && axis.isVertical && axis.edge === "right" ? barWindow._wingR : 0) + anchors.rightMargin: -(gothEnabled && axis.isVertical && axis.edge === "left" ? barWindow._wingR : 0) + anchors.topMargin: -(gothEnabled && !axis.isVertical && axis.edge === "bottom" ? barWindow._wingR : 0) + anchors.bottomMargin: -(gothEnabled && !axis.isVertical && axis.edge === "top" ? barWindow._wingR : 0) + + 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 + + property real wing: gothEnabled ? barWindow._wingR : 0 + + Behavior on wing { + enabled: root.width > 0 && root.height > 0 + NumberAnimation { + duration: Theme.shortDuration + easing.type: Easing.OutCubic + } + } + + property real rt: { + if (barConfig?.squareCorners ?? false) + return 0; + if (barWindow.hasMaximizedToplevel) + return 0; + return Theme.cornerRadius; + } + + Behavior on rt { + enabled: root.width > 0 && root.height > 0 + NumberAnimation { + duration: Theme.shortDuration + easing.type: Easing.OutCubic + } + } + + // M3 elevation shadow — Level 2 baseline (navigation bar), with per-bar override support + readonly property bool hasPerBarOverride: (barConfig?.shadowIntensity ?? 0) > 0 + readonly property var elevLevel: Theme.elevationLevel2 + readonly property bool shadowEnabled: (Theme.elevationEnabled && (typeof SettingsData !== "undefined" ? (SettingsData.barElevationEnabled ?? true) : false)) || hasPerBarOverride + readonly property string autoBarShadowDirection: isTop ? "top" : (isBottom ? "bottom" : (isLeft ? "left" : (isRight ? "right" : "top"))) + readonly property string globalShadowDirection: Theme.elevationLightDirection === "autoBar" ? autoBarShadowDirection : Theme.elevationLightDirection + readonly property string perBarShadowDirectionMode: barConfig?.shadowDirectionMode ?? "inherit" + readonly property string perBarManualShadowDirection: { + switch (barConfig?.shadowDirection) { + case "top": + case "topLeft": + case "topRight": + case "bottom": + return barConfig.shadowDirection; + default: + return "top"; + } + } + readonly property string effectiveShadowDirection: { + if (!hasPerBarOverride) + return globalShadowDirection; + switch (perBarShadowDirectionMode) { + case "autoBar": + return autoBarShadowDirection; + case "manual": + return perBarManualShadowDirection === "autoBar" ? autoBarShadowDirection : perBarManualShadowDirection; + default: + return globalShadowDirection; + } + } + + // Per-bar override values (when barConfig.shadowIntensity > 0) + readonly property real overrideBlurPx: (barConfig?.shadowIntensity ?? 0) * 0.2 + readonly property real overrideOpacity: (barConfig?.shadowOpacity ?? 60) / 100 + readonly property string overrideColorMode: barConfig?.shadowColorMode ?? "default" + readonly property color overrideBaseColor: { + switch (overrideColorMode) { + case "surface": + return Theme.surface; + case "primary": + return Theme.primary; + case "secondary": + return Theme.secondary; + case "custom": + return barConfig?.shadowCustomColor ?? "#000000"; + default: + return "#000000"; + } + } + + // Resolved values — per-bar override wins if set, otherwise use global M3 elevation + readonly property real shadowBlurPx: hasPerBarOverride ? overrideBlurPx : (elevLevel.blurPx ?? 8) + readonly property color shadowColor: hasPerBarOverride ? Theme.withAlpha(overrideBaseColor, overrideOpacity) : Theme.elevationShadowColor(elevLevel) + readonly property real shadowOffsetMagnitude: hasPerBarOverride ? (overrideBlurPx * 0.5) : Theme.elevationOffsetMagnitude(elevLevel, 4, effectiveShadowDirection) + readonly property real shadowOffsetX: Theme.elevationOffsetXFor(hasPerBarOverride ? null : elevLevel, effectiveShadowDirection, shadowOffsetMagnitude) + readonly property real shadowOffsetY: Theme.elevationOffsetYFor(hasPerBarOverride ? null : elevLevel, effectiveShadowDirection, shadowOffsetMagnitude) + + readonly property string mainPath: generatePathForPosition(width, height) + readonly property string borderFullPath: generateBorderFullPath(width, height) + readonly property string borderEdgePath: generateBorderEdgePath(width, height) + property bool mainPathCorrectShape: false + property bool borderFullPathCorrectShape: false + property bool borderEdgePathCorrectShape: false + + onMainPathChanged: { + if (width > 0 && height > 0) { + root: mainPathCorrectShape = true; + } + } + onBorderFullPathChanged: { + if (width > 0 && height > 0) { + root: borderFullPathCorrectShape = true; + } + } + onBorderEdgePathChanged: { + if (width > 0 && height > 0) { + root: borderEdgePathCorrectShape = true; + } + } + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton + z: -999 + onClicked: { + const activePopout = PopoutManager.getActivePopout(barWindow.screen); + if (activePopout) { + if (activePopout.dashVisible !== undefined) { + activePopout.dashVisible = false; + } else if (activePopout.notificationHistoryVisible !== undefined) { + activePopout.notificationHistoryVisible = false; + } else { + activePopout.close(); + } + } + TrayMenuManager.closeAllMenus(); + } + } + + ElevationShadow { + id: barShadow + visible: root.shadowEnabled && root.width > 0 && root.height > 0 + + // Size to the bar's rectangular body, excluding gothic wing extensions + x: root.isRight ? root.wing : 0 + y: root.isBottom ? root.wing : 0 + width: axis.isVertical ? (parent.width - root.wing) : parent.width + height: axis.isVertical ? parent.height : (parent.height - root.wing) + + shadowEnabled: root.shadowEnabled + level: root.hasPerBarOverride ? null : root.elevLevel + direction: root.effectiveShadowDirection + fallbackOffset: 4 + targetRadius: root.rt + targetColor: barWindow._bgColor + + shadowBlurPx: root.shadowBlurPx + shadowOffsetX: root.shadowOffsetX + shadowOffsetY: root.shadowOffsetY + shadowColor: root.shadowColor + blurMax: Theme.elevationBlurMax + } + + Loader { + id: barShape + anchors.fill: parent + active: mainPathCorrectShape + sourceComponent: Shape { + anchors.fill: parent + preferredRendererType: Shape.CurveRenderer + + ShapePath { + fillColor: barWindow._bgColor + strokeColor: "transparent" + strokeWidth: 0 + + PathSvg { + path: root.mainPath + } + } + } + } + + Loader { + id: barBorder + anchors.fill: parent + active: borderFullPathCorrectShape && borderEdgePathCorrectShape + + readonly property real _scale: CompositorService.getScreenScale(barWindow.screen) + readonly property real borderThickness: Math.ceil(Math.max(1, barConfig?.borderThickness ?? 1) * _scale) / _scale + readonly property real inset: borderThickness / 2 + 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 + sourceComponent: Shape { + id: barBorderShape + anchors.fill: parent + preferredRendererType: Shape.CurveRenderer + visible: barConfig?.borderEnabled ?? false + + ShapePath { + fillColor: "transparent" + strokeColor: barBorder.borderColor + strokeWidth: barBorder.borderThickness + joinStyle: ShapePath.RoundJoin + capStyle: ShapePath.FlatCap + + PathSvg { + path: barBorder.showFullBorder ? root.borderFullPath : root.borderEdgePath + } + } + } + } + + function generatePathForPosition(w, h) { + if (isTop) + return generateTopPath(w, h); + if (isBottom) + return generateBottomPath(w, h); + if (isLeft) + return generateLeftPath(w, h); + if (isRight) + return generateRightPath(w, h); + return generateTopPath(w, h); + } + + function generateBorderPathForPosition() { + if (isTop) + return generateTopBorderPath(); + if (isBottom) + return generateBottomBorderPath(); + if (isLeft) + return generateLeftBorderPath(); + if (isRight) + return generateRightBorderPath(); + return generateTopBorderPath(); + } + + function generateTopPath(w, h) { + h = h - wing; + const r = wing; + const cr = rt; + + 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(w, h) { + const fullH = h; + h = h - wing; + const r = wing; + const cr = rt; + + let d = `M ${cr} ${fullH}`; + d += ` L ${w - cr} ${fullH}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 0 ${w} ${fullH - 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 ${fullH - cr}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 0 ${cr} ${fullH}`; + d += " Z"; + return d; + } + + function generateLeftPath(w, h) { + w = w - wing; + const r = wing; + const cr = rt; + + 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(w, h) { + const fullW = w; + w = w - wing; + const r = wing; + const cr = rt; + + let d = `M ${fullW} ${cr}`; + d += ` L ${fullW} ${h - cr}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${fullW - 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 ${fullW - cr} 0`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${fullW} ${cr}`; + d += " Z"; + return d; + } + + function generateTopBorderPath() { + const w = barBorder.width; + const h = barBorder.height - wing; + const r = wing; + const cr = rt; + + 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; + + 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; + + 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; + + 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(fullW, fullH) { + const i = barBorder.inset; + const r = wing; + const cr = rt; + + if (isTop) { + const w = fullW - i * 2; + const h = fullH - wing - i * 2; + + 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} ${fullH - 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} ${fullH - 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 = fullW - i * 2; + const h = fullH - wing - i * 2; + + let d = `M ${i + cr} ${fullH - i}`; + d += ` L ${i + w - cr} ${fullH - i}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 0 ${i + w} ${fullH - 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} ${fullH - i - cr}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 0 ${i + cr} ${fullH - i}`; + d += " Z"; + return d; + } + + if (isLeft) { + const w = fullW - wing - i * 2; + const h = fullH - i * 2; + + 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 ${fullW - 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 ${fullW - 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 = fullW - wing - i * 2; + const h = fullH - i * 2; + + let d = `M ${fullW - i} ${i + cr}`; + d += ` L ${fullW - i} ${i + h - cr}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${fullW - 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 ${fullW - i - cr} ${i}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 1 ${fullW - i} ${i + cr}`; + d += " Z"; + return d; + } + + return ""; + } + + function generateBorderEdgePath(fullW, fullH) { + const i = barBorder.inset; + const r = wing; + const cr = rt; + + if (isTop) { + const w = fullW - i * 2; + const h = fullH - wing - i * 2; + + 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 = fullW - i * 2; + + 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 0 ${i + w - cr} ${i}`; + d += ` L ${i + cr} ${i}`; + if (cr > 0) + d += ` A ${cr} ${cr} 0 0 0 ${i} ${i + cr}`; + } + return d; + } + + if (isLeft) { + const w = fullW - wing - i * 2; + const h = fullH - i * 2; + + 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 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}`; + } + return d; + } + + if (isRight) { + const h = fullH - i * 2; + + 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 ""; + } +} -- cgit v1.3