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

commit2e363e9e79d31c0aff7d2d4ac16d6d82f2428da5
parentf2a89d57a5
authorLucas Galante <[email protected]>
date2026-08-27 12:50
fix: the open dropdown popover keeps its relief

PageContent never overrode RenderTarget::inset_plate, so the default
degraded the Dropdown's expanded trigger surface to a plain rounded
fill: the closed control had the groove ring and lip that
dropdown_relief carves for it, and lost them the moment the menu
opened. The override carves it for real — face to `rects`, ring to
`reliefs` (edges-only, drawn over the faces), which display_list
already emits in that order within a part.

The caller's depth is used verbatim rather than re-derived from the
handed height, as relief_inset would: the widget computes depth from
the TRIGGER's height, while the box passed here is the trigger plus the
revealed menu. Re-deriving would thicken the ring as the menu grew —
the same mistake dropdown_relief's own comment documents.

No doubled walls on the trigger band, where the app-side trigger carve
and this plate overlap: popover_pc's rects are emitted after
window_pc's reliefs, so the plate's opaque face covers the trigger's
ring before this one is drawn. Verified by pixel column — the popover
interior is byte-identical to the pre-fix build, and only the top and
bottom edges gained a groove/lip, at the same 2px+2px profile the
closed trigger has.

Co-Authored-By: Claude <[email protected]>

 src/pages/mod.rs | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/src/pages/mod.rs b/src/pages/mod.rs
index 907fc09..8c7e6ff 100644
--- a/src/pages/mod.rs
+++ b/src/pages/mod.rs
@@ -318,4 +318,29 @@ impl RenderTarget for PageContent {
     fn text_with_font_and_bounds(&mut self, content: &str, x: f32, y: f32, size: f32, color: [f32; 4], font: &str, bounds: Option<[f32; 4]>) {
         self.texts.push((content.to_string(), size, x, y, color, Some(font.to_string()), bounds));
     }
+
+    /// The flat-path bridge for a widget's flush inset plate — the Dropdown's
+    /// OPEN popover, which is its trigger surface grown over the unified box.
+    /// Without this override the default degrades it to a plain rounded fill,
+    /// so the menu lost the groove ring and lip the closed trigger has (the
+    /// `dropdown_relief` carve) the moment it expanded.
+    ///
+    /// The face and the walls go to different vecs on purpose — `reliefs` are
+    /// edges-only, drawn over the faces `rects` own — and `display_list` emits
+    /// this part's rects before its reliefs, so one call here lands as fill
+    /// then ring, in that order, within whichever part is being collected.
+    ///
+    /// **The caller's `depth` is used verbatim, NOT re-derived from `h`.** The
+    /// widget computes it from the TRIGGER's height; the box handed here is the
+    /// trigger plus the revealed menu, several times taller. `relief_inset`
+    /// would recompute `bevel_width().min(h * 0.2)` off that expanded height
+    /// and thicken the ring as the menu grows — the same mistake
+    /// [`dropdown_relief`] documents. A ring that swells during the open
+    /// animation is exactly the artifact this override exists to avoid.
+    fn inset_plate(&mut self, color: [f32; 4], x: f32, y: f32, w: f32, h: f32, radius: f32, depth: f32) {
+        self.rects.push((color, x, y, w, h, radius, (true, true, true, true)));
+        if cce_ui::layout::control_relief() {
+            self.reliefs.push((x, y, w, h, radius, depth, RELIEF_INSET));
+        }
+    }
 }