GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
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 {