From 8c549e14226ebc6ee454d8c40d2233f8cfb1705a Mon Sep 17 00:00:00 2001 From: rope Date: Tue, 28 Jul 2026 13:38:38 +0100 Subject: [PATCH] quickshell: melt edge-adjacent panels into the frame, centre night icon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Panels near a frame band left a visible seam instead of merging. The clamp now targets the frame's inner edge and the shader extends any surface within snapDist 4px INTO the band, so the SDF fuses them into one swollen shape — the launcher's launchBot trick, generalised to dropdowns, the session menu and the toast. Reverts the panelGap inset from the previous commit, which pushed in the wrong direction. qsIcon used anchors.verticalCenter and was centred only because the cell was qsIcon.width; at barWidth it sat at x=0. Co-Authored-By: Claude Opus 5 --- settings/quickshell.nix | 52 ++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/settings/quickshell.nix b/settings/quickshell.nix index 51e0cf8..238b64b 100644 --- a/settings/quickshell.nix +++ b/settings/quickshell.nix @@ -968,8 +968,20 @@ in // Panels grow rightward out of the bar column, so the // cross-axis is now vertical: the 8px inset that used to // be left/right is top/bottom. - readonly property real panelTop: chrome.y + 8 - readonly property real panelBottom: chrome.y + chrome.height - 8 + readonly property real rawTop: chrome.y + 8 + readonly property real rawBottom: chrome.y + chrome.height - 8 + // A surface that comes within snapDist of a frame band is + // extended 4px INTO it, so the SDF fuses the two into one + // swollen shape rather than leaving a visible seam and a + // stranded rounded corner. The launcher has always done + // this via launchBot; this generalises it to every panel. + readonly property real meltTop: Theme.frameWidth - 4 + readonly property real meltBot: bar.height - Theme.frameWidth + 4 + readonly property real snapDist: Theme.panelGap + 4 + readonly property real panelTop: rawTop <= Theme.frameWidth + snapDist + ? meltTop : rawTop + readonly property real panelBottom: rawBottom >= bar.height - Theme.frameWidth - snapDist + ? meltBot : rawBottom // The panel/toast/session centre-x uses (barWidth − 4): the // surface overlaps 4px into the bar so the two melt. readonly property real surfLeftX: Theme.barWidth - 4 @@ -982,13 +994,17 @@ in ? Qt.vector4d(surfLeftX + chrome.width / 2, (panelTop + panelBottom) / 2, 4 + chrome.width / 2, (panelBottom - panelTop) / 2) : Qt.vector4d(0, 0, 0, 0) + // Toast sits under the top frame band and melts up into it. + readonly property real toastBot: toastItem.y + 8 + _toastRect.height property vector4d toast: toastItem.visible && _toastRect.width > 0.5 - ? Qt.vector4d(surfLeftX + _toastRect.width / 2, toastItem.y + 8 + _toastRect.height / 2, - 4 + _toastRect.width / 2, _toastRect.height / 2) + ? Qt.vector4d(surfLeftX + _toastRect.width / 2, (meltTop + toastBot) / 2, + 4 + _toastRect.width / 2, (toastBot - meltTop) / 2) : Qt.vector4d(0, 0, 0, 0) + // Session menu sits in the bottom-left corner and melts + // down into the bottom frame band. property vector4d session: sessionMenu.visible - ? Qt.vector4d(surfLeftX + sessionMenu.width / 2, sessionMenu.y + sessionMenu.height / 2, - 4 + sessionMenu.width / 2, sessionMenu.height / 2) + ? Qt.vector4d(surfLeftX + sessionMenu.width / 2, (sessionMenu.y + meltBot) / 2, + 4 + sessionMenu.width / 2, (meltBot - sessionMenu.y) / 2) : Qt.vector4d(0, 0, 0, 0) // The launcher is the one surface that stays put: it still // grows from the bottom frame band at screen centre. @@ -1051,9 +1067,11 @@ in } // Unfolds rightward out of the bar at the bottom-left, - // level with the power button that opens it. + // level with the power button that opens it. Bottom edge + // sits on the frame's inner edge so the shader can melt + // the two together (meltBot) instead of leaving a seam. x: Theme.barWidth - y: Math.round(bar.height - Theme.frameWidth - height - 8) + y: Math.round(bar.height - Theme.frameWidth - height) width: openW height: openH visible: openW > 0.5 @@ -1889,9 +1907,11 @@ in SIcon { id: qsIcon - anchors.verticalCenter: parent.verticalCenter + // centerIn, not verticalCenter: the cell used to be + // qsIcon.width so horizontal centring was implicit. + anchors.centerIn: parent text: "nightlight" - font.pixelSize: 16 + font.pixelSize: 18 } function openQsDropdown() { @@ -2070,12 +2090,12 @@ in open = true; } - // Inset by panelGap so a panel that hits the clamp never - // sits flush on the frame band: flush fuses the two in the - // SDF and eats the panel's rounded corner. Outer max wins - // when a panel is taller than the space (yMax < yMin). - readonly property real yMin: Theme.frameWidth + Theme.panelGap - readonly property real yMax: bar.height - Theme.frameWidth - Theme.panelGap - height + // Clamp to the frame's inner edge. A panel that lands here + // is MEANT to fuse with the frame band — the shader melts + // it in (see meltTop/meltBot). Outer max wins when a panel + // is taller than the space (yMax < yMin). + readonly property real yMin: Theme.frameWidth + readonly property real yMax: bar.height - Theme.frameWidth - height x: Theme.barWidth y: Math.round(Math.max(yMin, Math.min(yMax, dropdownY - height / 2))) width: fullWidth + 4