git.lucas.co / cce-ui
GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git

commitff34736996b6157ed89aa3dacd05b8c4a74883de
parent641a9a4e79
authorLucas Galante <[email protected]>
date2026-07-21 10:22
feat: flush inset relief for buttons and dropdowns

New PaintCtx::inset_plate: a groove ring carved down around the control
and the control's own beveled lip rising back up inside — two
opposite-facing bevels leaving the face level with the surface, instead
of the raised plate. Button and Dropdown relief branches route through
it; transparent fills still degrade to edges-only lips.

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

 src/scene/paint.rs           | 24 ++++++++++++++++++++++++
 src/widget/input/button.rs   | 14 +++++---------
 src/widget/input/dropdown.rs |  9 ++++-----
 3 files changed, 33 insertions(+), 14 deletions(-)

diff --git a/src/scene/paint.rs b/src/scene/paint.rs
index cc28339..ed106b2 100644
--- a/src/scene/paint.rs
+++ b/src/scene/paint.rs
@@ -401,6 +401,30 @@ impl PaintCtx {
         self.push(Prim::Boss { rect, radii, depth, edges });
     }
 
+    /// A flush inset control: `rect`'s plate sits SUNKEN into the surface with
+    /// its face level with it — a groove ring carved around the control (the
+    /// outward wall steps down) and the control's own beveled lip rising back
+    /// up inside. Two opposite-facing bevels; the face never leaves the
+    /// surface plane. An opaque `color` fills the face (Bevel); transparent
+    /// degrades to edges-only (Boss), the surface below showing through as
+    /// the face. `depth` is the roll width of both walls; the groove ring is
+    /// one `depth` wide.
+    pub fn inset_plate(&mut self, rect: Rect, radii: Radii, color: [f32; 4], depth: f32) {
+        let outer = Rect {
+            x: rect.x - depth,
+            y: rect.y - depth,
+            width: rect.width + 2.0 * depth,
+            height: rect.height + 2.0 * depth,
+        };
+        let (r1, r2, r3, r4) = radii;
+        self.recess(outer, (r1 + depth, r2 + depth, r3 + depth, r4 + depth), depth);
+        if color[3] > 0.001 {
+            self.bevel(rect, radii, color, depth);
+        } else {
+            self.boss(rect, radii, depth);
+        }
+    }
+
     /// Raise a rim along `rect`'s boundary — see `Prim::Ridge`. `depth` is the
     /// full width of the bump (it straddles the outline by ±depth/2).
     pub fn ridge(&mut self, rect: Rect, radii: Radii, depth: f32) {
diff --git a/src/widget/input/button.rs b/src/widget/input/button.rs
index 61bcc79..b91aaf0 100644
--- a/src/widget/input/button.rs
+++ b/src/widget/input/button.rs
@@ -261,17 +261,13 @@ impl Paint for Button {
         let radius = crate::layout::button_corner_radius();
         let color = self.color();
 
-        // Raised style: one lit Bevel plate owns fill and edge — the rolled,
-        // lit rim replaces the flat border stroke. A transparent fill degrades
-        // to a Boss: edges-only, the plate below is the button's face (an
-        // opaque hover_color restores the filled bevel on hover).
+        // Relief style: a flush inset plate — the button sits sunken in a
+        // carved groove ring with its beveled lip rising back to the surface
+        // plane, face level with the surface. Transparent fills degrade to
+        // edges-only inside the groove (an opaque hover_color fills the face).
         if self.raised {
             let depth = crate::layout::bevel_width().min(h * 0.2);
-            if color[3] > 0.001 {
-                ctx.bevel(rect, (radius, radius, radius, radius), color, depth);
-            } else {
-                ctx.boss(rect, (radius, radius, radius, radius), depth);
-            }
+            ctx.inset_plate(rect, (radius, radius, radius, radius), color, depth);
         } else
         // Background (+ optional configured border), split by radius exactly as the legacy
         // `all_rounded_quads` (rounded) / `extra_quads` (square) overrides emitted it.
diff --git a/src/widget/input/dropdown.rs b/src/widget/input/dropdown.rs
index 6007e8f..7424b28 100644
--- a/src/widget/input/dropdown.rs
+++ b/src/widget/input/dropdown.rs
@@ -297,11 +297,10 @@ impl Dropdown {
         if self.raised && self.corner_frame.is_none() {
             let depth = crate::layout::bevel_width().min(visual_h * 0.2);
             let r4 = (radius, radius, radius, radius);
-            if raw_bg[3] > 0.001 {
-                ctx.bevel(Rect { x, y, width: w, height: visual_h }, r4, bg_color, depth);
-            } else {
-                ctx.boss(Rect { x, y, width: w, height: visual_h }, r4, depth);
-            }
+            // Flush inset plate: groove ring down, beveled lip back up, face
+            // level with the surface (transparent raw fill = edges only).
+            let face = if raw_bg[3] > 0.001 { bg_color } else { [0.0; 4] };
+            ctx.inset_plate(Rect { x, y, width: w, height: visual_h }, r4, face, depth);
             return;
         }
         if radius <= 0.0 {