diff --git a/quickshell/Common/SettingsData.qml b/quickshell/Common/SettingsData.qml index 17b52595a..264af868f 100644 --- a/quickshell/Common/SettingsData.qml +++ b/quickshell/Common/SettingsData.qml @@ -1028,7 +1028,9 @@ Singleton { "spacing": 4, "innerPadding": 4, "barInsetPadding": -1, + "barLengthPadding": 0, "bottomGap": 0, + "attachToScreenEdge": false, "transparency": 1.0, "widgetTransparency": 1.0, "squareCorners": false, @@ -1804,6 +1806,7 @@ Singleton { return { "shadowIntensity": config?.shadowIntensity ?? 0, "squareCorners": config?.squareCorners ?? false, + "attachToScreenEdge": config?.attachToScreenEdge ?? false, "gothCornersEnabled": config?.gothCornersEnabled ?? false, "borderEnabled": config?.borderEnabled ?? false }; @@ -1877,7 +1880,7 @@ Singleton { updateBarConfigs(); } - // Zeroes out connected-mode-hostile fields (shadow, square/goth corners, border). + // Zeroes out connected-mode-hostile fields (shadow, square/goth corners, edge attach, border). // Returns { configs, changed } — `configs` is the same ref when no change. function _sanitizeBarConfigsForConnectedFrame(configs) { if (!connectedFrameModeActive || !Array.isArray(configs)) @@ -1900,6 +1903,10 @@ Singleton { s.squareCorners = false; dirty = true; } + if (s.attachToScreenEdge ?? false) { + s.attachToScreenEdge = false; + dirty = true; + } if (s.gothCornersEnabled ?? false) { s.gothCornersEnabled = false; dirty = true; diff --git a/quickshell/Common/settings/SettingsSpec.js b/quickshell/Common/settings/SettingsSpec.js index 0a318b239..90b68aaca 100644 --- a/quickshell/Common/settings/SettingsSpec.js +++ b/quickshell/Common/settings/SettingsSpec.js @@ -577,7 +577,9 @@ var SPEC = { rightWidgets: ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"], spacing: 4, innerPadding: 4, + barLengthPadding: 0, bottomGap: 0, + attachToScreenEdge: false, transparency: 1.0, widgetTransparency: 1.0, squareCorners: false, diff --git a/quickshell/Modules/DankBar/BarCanvas.qml b/quickshell/Modules/DankBar/BarCanvas.qml index 9f0309cef..05bcc54f6 100644 --- a/quickshell/Modules/DankBar/BarCanvas.qml +++ b/quickshell/Modules/DankBar/BarCanvas.qml @@ -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; } diff --git a/quickshell/Modules/DankBar/DankBarBody.qml b/quickshell/Modules/DankBar/DankBarBody.qml index 3f796f925..facd18b90 100644 --- a/quickshell/Modules/DankBar/DankBarBody.qml +++ b/quickshell/Modules/DankBar/DankBarBody.qml @@ -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 diff --git a/quickshell/Modules/Settings/DankBarTab.qml b/quickshell/Modules/Settings/DankBarTab.qml index cc879d51d..285a90dc6 100644 --- a/quickshell/Modules/Settings/DankBarTab.qml +++ b/quickshell/Modules/Settings/DankBarTab.qml @@ -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"] diff --git a/quickshell/translations/settings_search_index.json b/quickshell/translations/settings_search_index.json index 085a7d95e..8d14b6292 100644 --- a/quickshell/translations/settings_search_index.json +++ b/quickshell/translations/settings_search_index.json @@ -787,6 +787,29 @@ ], "description": "Automatically hide the bar when the pointer moves away" }, + { + "section": "barLengthPadding", + "label": "Bar Length Padding", + "tabIndex": 3, + "category": "Dank Bar", + "keywords": [ + "bar", + "both", + "dank", + "ends", + "length", + "padding", + "panel", + "reduce", + "shorter", + "size", + "statusbar", + "taskbar", + "topbar", + "visible" + ], + "description": "Reduce the visible bar length from both ends" + }, { "section": "barClickThrough", "label": "Click Through", @@ -831,6 +854,34 @@ ], "icon": "dashboard" }, + { + "section": "barCornerStyle", + "label": "Corner Style", + "tabIndex": 3, + "category": "Dank Bar", + "keywords": [ + "attached", + "bar", + "choose", + "corner", + "corners", + "dank", + "edge", + "flush", + "meets", + "panel", + "radius", + "round", + "rounded", + "screen", + "square", + "statusbar", + "style", + "taskbar", + "topbar" + ], + "description": "Choose how the bar meets the screen edge" + }, { "section": "barDisplay", "label": "Display Assignment", @@ -1199,29 +1250,6 @@ ], "description": "Adjust the bar height via inner padding" }, - { - "section": "barSquareCorners", - "label": "Square Corners", - "tabIndex": 3, - "category": "Dank Bar", - "keywords": [ - "bar", - "corner", - "corners", - "dank", - "panel", - "radius", - "remove", - "round", - "rounded", - "rounding", - "square", - "statusbar", - "taskbar", - "topbar" - ], - "description": "Remove corner rounding from the bar" - }, { "section": "barAutoHideStrict", "label": "Strict auto-hide", @@ -2425,22 +2453,22 @@ "keywords": [ "background", "bar", - "corner", "corners", "dank", + "fully", + "invisible", + "make", "panel", "radius", - "remove", "round", "rounded", - "rounding", - "square", "statusbar", "taskbar", - "topbar" + "topbar", + "transparent" ], "icon": "rounded_corner", - "description": "Remove corner rounding from the bar" + "description": "Make the bar background fully transparent" }, { "section": "barAppearance",