diff --git a/settings/quickshell.nix b/settings/quickshell.nix index d834457..c16ee1b 100644 --- a/settings/quickshell.nix +++ b/settings/quickshell.nix @@ -1029,7 +1029,7 @@ in // Snapshot last, so a rect is always compared against // where it was exactly one tick ago. vector4d is a // value type, so this copies numbers, not handles. - prevRects = pushers.slice(); + prevRects = pushers.map(p => p.rect); } } @@ -1060,12 +1060,18 @@ in } // ── Shoved by the panels ──────────────────────────────── - // Bound to the very rects the frame shader melts into the - // chrome (cx, cy, hw, hh; hw <= 0 means "not on screen"), so - // what sweeps him aside is the panel outline you can actually - // see growing, not the cards riding inside it. + // Each pusher is { rect, push }: `rect` is the very vector4d + // the frame shader melts into the chrome (cx, cy, hw, hh; + // hw <= 0 means "not on screen"), so what sweeps him aside is + // the panel outline you can actually see. `push` is the unit + // direction that panel slides out in — a constant of the + // design, and not something worth deriving: the morph is + // 280ms of OutExpo, nearly all of it landing inside a single + // 33ms tick, so there is rarely a partly-grown rect to read a + // direction off of. property var pushers: [] property var prevRects: [] + readonly property real shoveSpeed: 18 function inRect(p, r) { return Math.abs(p.x - r.x) <= r.z + 6 && Math.abs(p.y - r.y) <= r.w + 6; @@ -1074,16 +1080,28 @@ in function checkShove() { let head = body[0], tail = body[segments - 1]; for (let i = 0; i < pushers.length; i++) { - let r = pushers[i], q = prevRects[i]; + let r = pushers[i].rect, q = prevRects[i]; if (!r || r.z < 0.5) continue; - if (!inRect(head, r)) continue; - if (!q || q.z < 0.5) { q = r; } // appeared already overlapping him - // Only an edge that is travelling outward carries him, - // and it carries him the way it is going: the dropdown - // grows rightward out of the bar, the launcher grows - // up out of the floor. A panel closing just lets go. - let dx = Math.max(0, (r.x + r.z) - (q.x + q.z)) + Math.min(0, (r.x - r.z) - (q.x - q.z)); - let dy = Math.max(0, (r.y + r.w) - (q.y + q.w)) + Math.min(0, (r.y - r.w) - (q.y - q.w)); + // Any part of him in the way is enough to be swept; + // only the head decides a turn-around. + let touched = false; + for (let s = 0; s < body.length && !touched; s++) + touched = inRect(body[s], r); + if (!touched) continue; + // Either it was not there a tick ago — the pop-out, + // and the usual case given how fast the morph is — or + // an edge has swept outward over him since. Both mean + // the panel arrived where he was standing. + let appeared = !q || q.z < 0.5; + let grew = !appeared && ( + (r.x + r.z) - (q.x + q.z) > 1 || (q.x - q.z) - (r.x - r.z) > 1 + || (r.y + r.w) - (q.y + q.w) > 1 || (q.y - q.w) - (r.y - r.w) > 1); + if (appeared || grew) { + worm.loose = true; + worm.vx = pushers[i].push.x * shoveSpeed; + worm.vy = pushers[i].push.y * shoveSpeed - 3; // -3: a little air + return; + } // Sitting still, it is simply solid: he walks into the // panel and turns around rather than crawling through // it, which is what made an open dropdown feel like it @@ -1092,15 +1110,7 @@ in // inside (he landed there) means walking on is the way // out, and reversing on that would just buzz him in // place against both edges. - if (Math.abs(dx) < 1 && Math.abs(dy) < 1) { - if (!inRect(tail, r)) reverse(); - return; - } - worm.loose = true; - // Clamped: the panel's first frame of OutExpo covers - // most of its width, which would fire him off screen. - worm.vx = Math.max(-22, Math.min(22, dx * 1.4)); - worm.vy = Math.max(-22, Math.min(22, dy * 1.4)) - 3; // -3: a little air + if (inRect(head, r) && !inRect(tail, r)) reverse(); return; } } @@ -6752,9 +6762,16 @@ in // Last child, so he crawls over the panels rather than under // them. Purely decorative, see Weird.qml. The pushers are the - // same rects the frame shader draws, so what shoves him is the - // panel outline itself as it grows. - Weird { pushers: [chromeSdf.panel, chromeSdf.launcher] } + // same rects the frame shader draws, paired with the way each + // one slides out: dropdowns and toasts rightward out of the + // bar column, the launcher up out of the bottom frame band. + Weird { + pushers: [ + { rect: chromeSdf.panel, push: Qt.point(1, 0) }, + { rect: chromeSdf.toast, push: Qt.point(1, 0) }, + { rect: chromeSdf.launcher, push: Qt.point(0, -1) } + ] + } } ''; };