git.lucas.co / cce-cloud
cloud storage client
git clone https://git.lucas.co/cce-cloud.git

commitb81ad2b000161dfb813750c63569a8b70f759cb5
parent087e4a8163
authorLucas Galante <lsgalante12@gmail.com>
date2026-10-06 08:57
feat(scrollbars): the list's bar rides its centre line, fading in over the rows

Off the tuple path: the idle copy (pills) goes under the list's translucent
bg every frame, and the fore copy fades in over the rows through
push_scrollbar_fore, where it was flat squares at the right edge on a hard
flip. The toolkit centres a sink-behind ScrollRegion's bar.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

 CLAUDE.md   |  8 ++++++++
 src/main.rs | 24 ++++++++++--------------
 2 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/CLAUDE.md b/CLAUDE.md
index 3789238..7733831 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -28,6 +28,14 @@ The list's scrollbar/viewport math is the toolkit's `cce_ui::widget::ScrollRegio
 `get_draw_y` its partially-visible-rows contract, which paint, click and hover all
 virtualize on.
 
+Its bar is the DE's one scrollbar (cce-ui's CLAUDE.md, "Every scrollbar rides a
+centre line, behind the plate"): `with_sink_behind(true)`, so it rides the
+list's centre line over the rows, idles under the list's translucent bg fill
+(`push_scrollbar_prims` before the fill, every frame) and fades in over the
+rows while a scroll holds it (`push_scrollbar_fore` after them). Until
+2026-10-06 it sat at the right edge as flat squares on a hard flip, through the
+tuple path (`push_quads` / `push_scrollbar_quads`).
+
 ## Build, test, run
 
 ```sh
diff --git a/src/main.rs b/src/main.rs
index 0ffabf3..130a1df 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1425,12 +1425,13 @@ impl cce_ui::widget::Paint for FuzzelWidget {
         let hc = cce_ui::color::highlight_primary_color();
         ctx.recess_tinted(well, (0.0, 0.0, 0.0, 0.0), depth, [hc[0], hc[1], hc[2]]);
 
-        // ScrollBox quads
-        let mut quads = Vec::new();
-        self.scroll_box.push_quads(&mut quads);
-        for (qx, qy, qw, qh, qc) in quads {
-            ctx.quad(Rect { x: qx, y: qy, width: qw, height: qh }, qc);
-        }
+        // The list's scrollbar idles UNDER its translucent bg fill, every
+        // frame: down the list's centre line (the toolkit centres a
+        // sink-behind bar), dimly seen through the fill, taking no press.
+        // The fore copy fades in over the rows below while a scroll holds it.
+        self.scroll_box.push_scrollbar_prims(ctx);
+        let sb = &self.scroll_box;
+        ctx.quad(Rect { x: sb.x, y: sb.y, width: sb.w, height: sb.h }, cce_ui::color::list_bg_color());
 
         // The list content — selection chip, icons, row labels — under the
         // list-viewport clip: `get_draw_y` returns PARTIALLY visible rows (the
@@ -1501,14 +1502,9 @@ impl cce_ui::widget::Paint for FuzzelWidget {
             }
         });
 
-        // The raised scrollbar rides over the rows while a scroll holds it up
-        // (the sunk layer went under the list bg inside push_quads). The bar
-        // was previously never drawn at all — grabbable but invisible.
-        let mut bar = Vec::new();
-        self.scroll_box.push_scrollbar_quads(&mut bar);
-        for (qx, qy, qw, qh, qc) in bar {
-            ctx.quad(Rect { x: qx, y: qy, width: qw, height: qh }, qc);
-        }
+        // The fore copy rides over the rows at the fade, so the raise and the
+        // sink are a fade rather than a flip.
+        self.scroll_box.push_scrollbar_fore(ctx);
 
         // Prompt/query line and the empty-state notice — outside the list clip.
         for l in self.own_labels() {