git.lucas.co / cce-files
file manager
git clone https://git.lucas.co/cce-files.git

commit751d183cd8ec60c0cf307d10c7f54f392bc174cd
parentbccefdd4ff
authorLucas Galante <[email protected]>
date2026-08-15 11:03
fix: carve the dropdown's ring at the lip's depth, not the ring's

`dropdown_relief` hand-rolled the pair `PaintCtx::inset_plate` expands to —
`recess` over a rect expanded by depth/2, then `boss` — instead of calling
it. That is the same treatment `Dropdown::paint_background` applies, so the
flat mirror was structurally right, but one number was not.

`relief_recessed` derives its depth from the height it is HANDED, and what
it was handed was the ALREADY-expanded height: min(9.3, 28.8*0.2) = 5.76,
against the lip's min(9.3, 24*0.2) = 4.8. A 5.76 wall with only a 2.4
expansion over-runs the lip by ~1px instead of meeting it, which is exactly
what inset_plate's contract rules out — "the ring is expanded by depth/2, so
the descending wall meets the rising lip in a tight V-groove with no flat
floor between them". The over-run dug that flat floor.

Routing through `relief_inset` -> `WidgetFx::Inset` -> `pc.inset_plate`
reaches the widget's own call, so the two cannot drift again. That path was
already wired end to end and had zero callers.

Pixel-diffed against the previous binary, same directory and window size
(the render is deterministic across restarts — three separate launches of
the old binary gave byte-identical captures, which is what makes the diff
attributable). The diff bounding box is (750,13)-(1011,83): the dropdown and
nothing else in the 2064x1008 window. The lit lip is byte-identical, since
its 4.8 was already correct; the ring's outer edge pulls in ~1px and the
false floor at the groove bottom lifts ~5/255. Live-verified after: the menu
opens, selecting Space switches the page, and the ring tracks the control to
the different coordinates that page lays it out at.

 src/pages/mod.rs | 24 +++++++++++++++---------
 1 file changed, 15 insertions(+), 9 deletions(-)

diff --git a/src/pages/mod.rs b/src/pages/mod.rs
index 30337fd..098bab7 100644
--- a/src/pages/mod.rs
+++ b/src/pages/mod.rs
@@ -67,6 +67,15 @@ pub fn breadcrumb_relief(
 /// only quads and text, so the carve is app-side — the same story as
 /// [`breadcrumb_relief`], which is the well-and-plate this pairs with.
 ///
+/// It reaches the SAME `inset_plate` call the widget makes, via
+/// [`PageContent::relief_inset`] → `WidgetFx::Inset`. It used to hand-roll the
+/// pair `inset_plate` expands to (`relief_recessed` over an expanded rect, then
+/// `relief_raised`) — which got the ring's depth wrong, because
+/// `relief_recessed` derives depth from the height it is HANDED, and that was
+/// the already-expanded one: a 5.76px wall against a 4.8px lip, so the
+/// descending wall over-ran the lip instead of meeting it in the tight V-groove
+/// with no flat floor that `inset_plate` documents.
+///
 /// **Carve it into `window_pc`, AFTER the page's `view()` has run.** Two
 /// constraints pin it there, and they pull in opposite directions:
 ///
@@ -82,16 +91,13 @@ pub fn breadcrumb_relief(
 ///   shows both as overlay fallback, so this is compositing order, not
 ///   plate grouping.)
 pub fn dropdown_relief(pc: &mut PageContent, rect: cce_ui::scene::layout::Rect) {
-    let r = cce_ui::layout::dropdown_corner_radius();
-    let g = cce_ui::layout::bevel_width().min(rect.height * 0.2) * 0.5;
-    pc.relief_recessed(
-        rect.x - g,
-        rect.y - g,
-        rect.width + 2.0 * g,
-        rect.height + 2.0 * g,
-        r + g,
+    pc.relief_inset(
+        rect.x,
+        rect.y,
+        rect.width,
+        rect.height,
+        cce_ui::layout::dropdown_corner_radius(),
     );
-    pc.relief_raised(rect.x, rect.y, rect.width, rect.height, r);
 }
 
 pub const RELIEF_RECESSED: u8 = 0;