quickshell: bury melt joints by a full corner radius

Panels buried only 8px into the bar while their corner radius was 24,
so 16px of rounded corner stuck out past the joint: the outline pinched
where the corner turned, then the fillet bulged back out. That is the
balloon at the connection point.

meltInto now tracks Theme.radius, so the whole corner ends up inside
the band it merges with and only straight edges reach the junction —
which is what smin is meant to fillet. Applies to the panel, toast and
launcher. meltK follows radius / 2 so the fillet scales with the one
rounding knob instead of drifting out of step.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
rope 2026-07-28 14:05:39 +01:00
parent b2e4e9863b
commit 0a6a23aa8a

View file

@ -975,21 +975,27 @@ in
// be left/right is top/bottom. // be left/right is top/bottom.
readonly property real rawTop: chrome.y + 8 readonly property real rawTop: chrome.y + 8
readonly property real rawBottom: chrome.y + chrome.height - 8 readonly property real rawBottom: chrome.y + chrome.height - 8
// A surface that comes within snapDist of a frame band is // How deep a surface buries itself in the band it merges
// extended 4px INTO it, so the SDF fuses the two into one // with. This MUST be >= the panel corner radius. A rounded
// swollen shape rather than leaving a visible seam and a // corner curves away from the edge over exactly panelR
// stranded rounded corner. The launcher has always done // pixels, so burying less than that leaves part of the
// this via launchBot; this generalises it to every panel. // curve sticking out past the joint: the outline pinches in
readonly property real meltTop: Theme.frameWidth - 4 // where the corner turns, then the fillet bulges back out
readonly property real meltBot: bar.height - Theme.frameWidth + 4 // the "ballooned at the connection point" look. Bury the
// whole corner and only straight edges reach the junction,
// which is what smin is meant to fillet.
readonly property real meltInto: Theme.radius
readonly property real meltTop: Theme.frameWidth - meltInto
readonly property real meltBot: bar.height - Theme.frameWidth + meltInto
// Trigger distance is about proximity, not burial depth.
readonly property real snapDist: Theme.panelGap + 4 readonly property real snapDist: Theme.panelGap + 4
readonly property real panelTop: rawTop <= Theme.frameWidth + snapDist readonly property real panelTop: rawTop <= Theme.frameWidth + snapDist
? meltTop : rawTop ? meltTop : rawTop
readonly property real panelBottom: rawBottom >= bar.height - Theme.frameWidth - snapDist readonly property real panelBottom: rawBottom >= bar.height - Theme.frameWidth - snapDist
? meltBot : rawBottom ? meltBot : rawBottom
// The panel/toast/session centre-x uses (barWidth 4): the // Left edge lands at (barWidth meltInto): the surface
// surface overlaps 4px into the bar so the two melt. // buries a full corner radius inside the bar column.
readonly property real surfLeftX: Theme.barWidth - 4 readonly property real surfLeftX: Theme.barWidth - meltInto / 2
property vector4d cutout: Qt.vector4d( property vector4d cutout: Qt.vector4d(
(Theme.barWidth + bar.width - Theme.frameWidth) / 2, (Theme.barWidth + bar.width - Theme.frameWidth) / 2,
bar.height / 2, bar.height / 2,
@ -997,17 +1003,17 @@ in
bar.height / 2 - Theme.frameWidth) bar.height / 2 - Theme.frameWidth)
property vector4d panel: chrome.visible property vector4d panel: chrome.visible
? Qt.vector4d(surfLeftX + chrome.width / 2, (panelTop + panelBottom) / 2, ? Qt.vector4d(surfLeftX + chrome.width / 2, (panelTop + panelBottom) / 2,
4 + chrome.width / 2, (panelBottom - panelTop) / 2) meltInto / 2 + chrome.width / 2, (panelBottom - panelTop) / 2)
: Qt.vector4d(0, 0, 0, 0) : Qt.vector4d(0, 0, 0, 0)
// Toast sits under the top frame band and melts up into it. // Toast sits under the top frame band and melts up into it.
readonly property real toastBot: toastItem.y + 8 + _toastRect.height readonly property real toastBot: toastItem.y + 8 + _toastRect.height
property vector4d toast: toastItem.visible && _toastRect.width > 0.5 property vector4d toast: toastItem.visible && _toastRect.width > 0.5
? Qt.vector4d(surfLeftX + _toastRect.width / 2, (meltTop + toastBot) / 2, ? Qt.vector4d(surfLeftX + _toastRect.width / 2, (meltTop + toastBot) / 2,
4 + _toastRect.width / 2, (toastBot - meltTop) / 2) meltInto / 2 + _toastRect.width / 2, (toastBot - meltTop) / 2)
: Qt.vector4d(0, 0, 0, 0) : Qt.vector4d(0, 0, 0, 0)
// The launcher is the one surface that stays put: it still // The launcher is the one surface that stays put: it still
// grows from the bottom frame band at screen centre. // grows from the bottom frame band at screen centre.
readonly property real launchBot: bar.height - Theme.frameWidth + 4 readonly property real launchBot: bar.height - Theme.frameWidth + meltInto
property vector4d launcher: launcherPanel.visible property vector4d launcher: launcherPanel.visible
? Qt.vector4d(launcherPanel.x + launcherPanel.width / 2, (launcherPanel.y + launchBot) / 2, ? Qt.vector4d(launcherPanel.x + launcherPanel.width / 2, (launcherPanel.y + launchBot) / 2,
launcherPanel.width / 2, (launchBot - launcherPanel.y) / 2) launcherPanel.width / 2, (launchBot - launcherPanel.y) / 2)
@ -1017,7 +1023,9 @@ in
property vector2d res: Qt.vector2d(width, height) property vector2d res: Qt.vector2d(width, height)
property real cutoutR: Theme.radius property real cutoutR: Theme.radius
property real panelR: Theme.radius property real panelR: Theme.radius
property real meltK: 12 // Half the corner radius: the fillet scales with the
// one rounding knob instead of drifting out of step.
property real meltK: Theme.radius / 2
property real borderW: Theme.borderWidth property real borderW: Theme.borderWidth
fragmentShader: "file://${chromeShader}" fragmentShader: "file://${chromeShader}"
} }