feat(dankbar): corner style & bar length padding (#3085)

* feat(dock): attach bar to screen edge

* feat(dock): add bar length padding

* feat(dock): expand bar padding range

* refactor(dock): group bar corner settings

* fix(i18n): avoid attached term variant

* fix(settings): group corner style with goth corners

* fix(dankbar): attach flush bars to the screen edge

---------

Co-authored-by: bbedward <[email protected]>
This commit is contained in:
Huỳnh Thiện Lộcandbbedward authored and GitHub committed 2026-08-17 13:22:09 -04:00
1 parent 8485d66139
commit 9abaf4051e
6 files changed
+177 -87

No files matched your search

+41 -36
View File
@@ -29,6 +29,7 @@ Item {
readonly property bool isBottom: barPos === SettingsData.Position.Bottom
readonly property bool isLeft: barPos === SettingsData.Position.Left
readonly property bool isRight: barPos === SettingsData.Position.Right
readonly property bool edgeAttached: (barConfig?.attachToScreenEdge ?? false) && !frameShapesBar
property real wing: gothEnabled ? barWindow._wingR : 0
@@ -204,10 +205,10 @@ Item {
// wing-side body corners are square where the gothic fillets attach;
// rounding the shadow there leaves a shadow-filled notch under the
// translucent bar fill (#2975)
topLeftRadius: root.gothEnabled && (root.isBottom || root.isRight) ? 0 : root.rt
topRightRadius: root.gothEnabled && (root.isBottom || root.isLeft) ? 0 : root.rt
bottomLeftRadius: root.gothEnabled && (root.isTop || root.isRight) ? 0 : root.rt
bottomRightRadius: root.gothEnabled && (root.isTop || root.isLeft) ? 0 : root.rt
topLeftRadius: root.edgeAttached && (root.isTop || root.isLeft) ? 0 : (root.gothEnabled && (root.isBottom || root.isRight) ? 0 : root.rt)
topRightRadius: root.edgeAttached && (root.isTop || root.isRight) ? 0 : (root.gothEnabled && (root.isBottom || root.isLeft) ? 0 : root.rt)
bottomLeftRadius: root.edgeAttached && (root.isBottom || root.isLeft) ? 0 : (root.gothEnabled && (root.isTop || root.isRight) ? 0 : root.rt)
bottomRightRadius: root.edgeAttached && (root.isBottom || root.isRight) ? 0 : (root.gothEnabled && (root.isTop || root.isLeft) ? 0 : root.rt)
// barShape below is the sole painter of the bar; a fill here doubles
// the alpha of translucent bars while the wings stay single-painted
targetColor: "transparent"
@@ -298,7 +299,7 @@ Item {
h = h - wing;
const r = wing;
const cr = rt;
const crE = frameShapesBar ? 0 : cr;
const crE = frameShapesBar || edgeAttached ? 0 : cr;
let d = `M ${crE} 0`;
d += ` L ${w - crE} 0`;
@@ -329,7 +330,7 @@ Item {
h = h - wing;
const r = wing;
const cr = rt;
const crE = frameShapesBar ? 0 : cr;
const crE = frameShapesBar || edgeAttached ? 0 : cr;
let d = `M ${crE} ${fullH}`;
d += ` L ${w - crE} ${fullH}`;
@@ -359,7 +360,7 @@ Item {
w = w - wing;
const r = wing;
const cr = rt;
const crE = frameShapesBar ? 0 : cr;
const crE = frameShapesBar || edgeAttached ? 0 : cr;
let d = `M 0 ${crE}`;
d += ` L 0 ${h - crE}`;
@@ -390,7 +391,7 @@ Item {
w = w - wing;
const r = wing;
const cr = rt;
const crE = frameShapesBar ? 0 : cr;
const crE = frameShapesBar || edgeAttached ? 0 : cr;
let d = `M ${fullW} ${crE}`;
d += ` L ${fullW} ${h - crE}`;
@@ -514,11 +515,12 @@ Item {
if (isTop) {
const w = fullW - i * 2;
const h = fullH - wing - i * 2;
const crE = edgeAttached ? 0 : cr;
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}`;
let d = `M ${i + crE} ${i}`;
d += ` L ${i + w - crE} ${i}`;
if (crE > 0)
d += ` A ${crE} ${crE} 0 0 1 ${i + w} ${i + crE}`;
if (r > 0) {
d += ` L ${i + w} ${fullH - i}`;
d += ` A ${r} ${r} 0 0 0 ${i + w - r} ${i + h}`;
@@ -532,9 +534,9 @@ Item {
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 += ` L ${i} ${i + crE}`;
if (crE > 0)
d += ` A ${crE} ${crE} 0 0 1 ${i + crE} ${i}`;
d += " Z";
return d;
}
@@ -542,11 +544,12 @@ Item {
if (isBottom) {
const w = fullW - i * 2;
const h = fullH - wing - i * 2;
const crE = edgeAttached ? 0 : cr;
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}`;
let d = `M ${i + crE} ${fullH - i}`;
d += ` L ${i + w - crE} ${fullH - i}`;
if (crE > 0)
d += ` A ${crE} ${crE} 0 0 0 ${i + w} ${fullH - i - crE}`;
if (r > 0) {
d += ` L ${i + w} ${i}`;
d += ` A ${r} ${r} 0 0 1 ${i + w - r} ${i + r}`;
@@ -560,9 +563,9 @@ Item {
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 += ` L ${i} ${fullH - i - crE}`;
if (crE > 0)
d += ` A ${crE} ${crE} 0 0 0 ${i + crE} ${fullH - i}`;
d += " Z";
return d;
}
@@ -570,11 +573,12 @@ Item {
if (isLeft) {
const w = fullW - wing - i * 2;
const h = fullH - i * 2;
const crE = edgeAttached ? 0 : cr;
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}`;
let d = `M ${i} ${i + crE}`;
d += ` L ${i} ${i + h - crE}`;
if (crE > 0)
d += ` A ${crE} ${crE} 0 0 0 ${i + crE} ${i + h}`;
if (r > 0) {
d += ` L ${fullW - i} ${i + h}`;
d += ` A ${r} ${r} 0 0 1 ${i + w} ${i + h - r}`;
@@ -588,9 +592,9 @@ Item {
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 + crE} ${i}`;
if (crE > 0)
d += ` A ${crE} ${crE} 0 0 0 ${i} ${i + crE}`;
d += " Z";
return d;
}
@@ -598,11 +602,12 @@ Item {
if (isRight) {
const w = fullW - wing - i * 2;
const h = fullH - i * 2;
const crE = edgeAttached ? 0 : cr;
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}`;
let d = `M ${fullW - i} ${i + crE}`;
d += ` L ${fullW - i} ${i + h - crE}`;
if (crE > 0)
d += ` A ${crE} ${crE} 0 0 1 ${fullW - i - crE} ${i + h}`;
if (r > 0) {
d += ` L ${i} ${i + h}`;
d += ` A ${r} ${r} 0 0 0 ${i + r} ${i + h - r}`;
@@ -616,9 +621,9 @@ Item {
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 += ` L ${fullW - i - crE} ${i}`;
if (crE > 0)
d += ` A ${crE} ${crE} 0 0 1 ${fullW - i} ${i + crE}`;
d += " Z";
return d;
}
+19 -9
View File
@@ -559,7 +559,8 @@ Item {
shouldHideForWindows = filtered.length > 0;
}
property real effectiveSpacing: (FrameTransitionState.effectiveFrameEnabled && usesFrameBarChrome) ? 0 : ((flattenForMaximizedWindow && hasMaximizedToplevel) ? 0 : (barConfig?.spacing ?? 4))
readonly property bool edgeAttached: (barConfig?.attachToScreenEdge ?? false) && !(FrameTransitionState.effectiveFrameEnabled && usesFrameBarChrome)
property real effectiveSpacing: (FrameTransitionState.effectiveFrameEnabled && usesFrameBarChrome) ? 0 : ((edgeAttached || (flattenForMaximizedWindow && hasMaximizedToplevel)) ? 0 : (barConfig?.spacing ?? 4))
Behavior on effectiveSpacing {
enabled: barWindow.hostWindow?.visible ?? false
@@ -571,6 +572,13 @@ Item {
readonly property int notificationCount: NotificationService.notifications.length
readonly property real effectiveBarThickness: (FrameTransitionState.effectiveFrameEnabled && usesFrameBarChrome) ? SettingsData.frameBarSize : Theme.snap(Math.max(barWindow.widgetThickness + (barConfig?.innerPadding ?? 4) + 4, Theme.barHeight - 4 - (8 - (barConfig?.innerPadding ?? 4))), _dpr)
readonly property real effectiveBarLengthPadding: {
if ((FrameTransitionState.effectiveFrameEnabled && usesFrameBarChrome) || (flattenForMaximizedWindow && hasMaximizedToplevel))
return 0;
const pad = Math.max(0, barConfig?.barLengthPadding ?? 0);
const length = isVertical ? height : width;
return length > 0 ? Math.min(pad, Math.max(0, length / 2 - effectiveSpacing)) : pad;
}
readonly property bool effectiveOpenOnOverview: FrameTransitionState.effectiveFrameEnabled ? SettingsData.frameShowOnOverview : (barConfig?.openOnOverview ?? false)
readonly property real widgetThickness: Theme.snap(Math.max(20, 26 + (barConfig?.innerPadding ?? 4) * 0.6), _dpr)
@@ -766,6 +774,7 @@ Item {
id: inputMask
readonly property int barThickness: Theme.px(barWindow.effectiveBarThickness + barWindow.effectiveSpacing, barWindow._dpr)
readonly property int lengthPaddingPx: Theme.px(barWindow.effectiveBarLengthPadding, barWindow._dpr)
readonly property bool inOverviewWithShow: CompositorService.isNiri && NiriService.inOverview && barWindow.effectiveOpenOnOverview
readonly property bool effectiveVisible: (barConfig?.visible ?? true) || inOverviewWithShow
@@ -775,7 +784,7 @@ Item {
x: {
if (!axis.isVertical) {
return 0;
return lengthPaddingPx;
} else {
switch (barPos) {
case SettingsData.Position.Left:
@@ -789,7 +798,7 @@ Item {
}
y: {
if (axis.isVertical) {
return 0;
return lengthPaddingPx;
} else {
switch (barPos) {
case SettingsData.Position.Top:
@@ -801,8 +810,8 @@ Item {
}
}
}
width: axis.isVertical ? maskThickness : parent.width
height: axis.isVertical ? parent.height : maskThickness
width: axis.isVertical ? maskThickness : parent.width - lengthPaddingPx * 2
height: axis.isVertical ? parent.height - lengthPaddingPx * 2 : maskThickness
}
readonly property bool clickThroughEnabled: barConfig?.clickThrough ?? false
@@ -1074,11 +1083,12 @@ Item {
Item {
id: barUnitInset
property int spacingPx: Theme.px(barWindow.effectiveSpacing, barWindow._dpr)
property int lengthPaddingPx: Theme.px(barWindow.effectiveBarLengthPadding, barWindow._dpr)
anchors.fill: parent
anchors.leftMargin: !barWindow.isVertical ? spacingPx : (axis.edge === "left" ? spacingPx : 0)
anchors.rightMargin: !barWindow.isVertical ? spacingPx : (axis.edge === "right" ? spacingPx : 0)
anchors.topMargin: barWindow.isVertical ? (barWindow.hasAdjacentTopBar ? 0 : spacingPx) : (axis.outerVisualEdge() === "bottom" ? 0 : spacingPx)
anchors.bottomMargin: barWindow.isVertical ? (barWindow.hasAdjacentBottomBar ? 0 : spacingPx) : (axis.outerVisualEdge() === "bottom" ? spacingPx : 0)
anchors.leftMargin: !barWindow.isVertical ? spacingPx + lengthPaddingPx : (axis.edge === "left" ? spacingPx : 0)
anchors.rightMargin: !barWindow.isVertical ? spacingPx + lengthPaddingPx : (axis.edge === "right" ? spacingPx : 0)
anchors.topMargin: barWindow.isVertical ? (barWindow.hasAdjacentTopBar ? 0 : spacingPx) + lengthPaddingPx : (axis.outerVisualEdge() === "bottom" ? 0 : spacingPx)
anchors.bottomMargin: barWindow.isVertical ? (barWindow.hasAdjacentBottomBar ? 0 : spacingPx) + lengthPaddingPx : (axis.outerVisualEdge() === "bottom" ? spacingPx : 0)
BarCanvas {
id: barBackground
+50 -12
View File
@@ -136,7 +136,9 @@ Item {
rightWidgets: defaultBar.rightWidgets || [],
spacing: defaultBar.spacing ?? 4,
innerPadding: defaultBar.innerPadding ?? 4,
barLengthPadding: defaultBar.barLengthPadding ?? 0,
bottomGap: defaultBar.bottomGap ?? 0,
attachToScreenEdge: defaultBar.attachToScreenEdge ?? false,
transparency: defaultBar.transparency ?? 1.0,
widgetTransparency: defaultBar.widgetTransparency ?? 1.0,
squareCorners: defaultBar.squareCorners ?? false,
@@ -1029,6 +1031,30 @@ Item {
}
}
SettingsSliderRow {
id: barLengthPaddingSlider
settingKey: "barLengthPadding"
visible: !SettingsData.frameEnabled
text: I18n.tr("Bar Length Padding")
description: I18n.tr("Reduce the visible bar length from both ends")
tags: ["bar", "length", "padding", "size", "shorter"]
unit: "px"
minimum: 0
maximum: 512
defaultValue: 0
value: selectedBarConfig?.barLengthPadding ?? 0
onSliderDragFinished: finalValue => SettingsData.updateBarConfig(selectedBarId, {
barLengthPadding: finalValue
})
Binding {
target: barLengthPaddingSlider
property: "value"
value: selectedBarConfig?.barLengthPadding ?? 0
restoreMode: Binding.RestoreBinding
}
}
SettingsToggleRow {
visible: !SettingsData.frameEnabled
text: I18n.tr("Sync Bar Inset Padding")
@@ -1166,18 +1192,6 @@ Item {
reason: I18n.tr("Managed by Frame")
}
SettingsToggleRow {
settingKey: "barSquareCorners"
tags: ["square", "corners", "rounding"]
text: I18n.tr("Square Corners")
description: I18n.tr("Remove corner rounding from the bar")
visible: !SettingsData.frameEnabled
checked: selectedBarConfig?.squareCorners ?? false
onToggled: checked => SettingsData.updateBarConfig(selectedBarId, {
squareCorners: checked
})
}
SettingsToggleRow {
settingKey: "barNoBackground"
tags: ["transparent", "background", "invisible"]
@@ -1230,6 +1244,30 @@ Item {
opacity: 0.15
}
SettingsButtonGroupRow {
settingKey: "barCornerStyle"
tags: ["rounded", "attached", "square", "corners", "edge", "screen", "flush"]
text: I18n.tr("Corner Style")
description: I18n.tr("Choose how the bar meets the screen edge")
visible: !SettingsData.frameEnabled
model: [I18n.tr("Rounded", "bar corner style option"), I18n.tr("Flush", "bar corner style option"), I18n.tr("Square", "bar corner style option")]
currentIndex: {
if (selectedBarConfig?.squareCorners ?? false)
return 2;
if (selectedBarConfig?.attachToScreenEdge ?? false)
return 1;
return 0;
}
onSelectionChanged: (index, selected) => {
if (!selected)
return;
SettingsData.updateBarConfig(selectedBarId, {
squareCorners: index === 2,
attachToScreenEdge: index === 1
});
}
}
SettingsToggleRow {
settingKey: "barGothCorners"
tags: ["goth", "corners", "concave", "cutout"]