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

commit18283c3970d91de2eb54a10b48e2ab3e34b7d02c
parentfda31341f8
authorLucas Galante <[email protected]>
date2026-09-08 21:50
fix(focus): the ring survives the flat-host bridge

Hosts that draw through `layout::render_widget` (cce-files,
cce-system-interface, …) never saw a focused plate's ring: the bridge's
Trough arm handed the target a plain `inset_plate`, and a Boss carve had no
tint to carry. `RenderTarget::inset_plate_tinted` (default: the plain plate;
PaintCtx: face fill plus a tinted trough, also inherent as
`PaintCtx::inset_plate_tinted`) and `CarveKind::Boss { tint }` carry it
through, and `control_plate`'s flush-tinted branch uses the same entry.

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

 src/layout.rs                         | 20 +++++++++++++++-----
 src/scene/paint.rs                    | 26 ++++++++++++++++++--------
 src/widget/container/parameters_bg.rs |  2 +-
 src/widget/input/checkbox.rs          |  2 +-
 4 files changed, 35 insertions(+), 15 deletions(-)

diff --git a/src/layout.rs b/src/layout.rs
index cd635df..3b82d03 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -3572,7 +3572,7 @@ pub enum CarveKind {
     /// `tint` lights the rim in the focus accent (`recess_tinted`).
     Recess { tint: Option<[f32; 3]> },
     /// Interior one step UP ([`crate::scene::paint::PaintCtx::boss_edges`]).
-    Boss,
+    Boss { tint: Option<[f32; 3]> },
     /// A FLUSH inset ([`crate::scene::paint::PaintCtx::trough_edges`]): the
     /// interior stays level with the surface and a valley seam runs the
     /// boundary — the closed dropdown's chrome, for a control that is part
@@ -3615,6 +3615,12 @@ pub trait RenderTarget {
     fn inset_plate(&mut self, color: [f32; 4], x: f32, y: f32, w: f32, h: f32, radius: f32, _depth: f32) {
         self.rect_with_radius(color, x, y, w, h, radius);
     }
+    /// [`inset_plate`](Self::inset_plate) with the rim lit — the focused
+    /// control plate's ring (`ControlPlate::with_tint`). Hosts without relief
+    /// prims draw the plain plate.
+    fn inset_plate_tinted(&mut self, color: [f32; 4], x: f32, y: f32, w: f32, h: f32, radius: f32, depth: f32, _tint: [f32; 3]) {
+        self.inset_plate(color, x, y, w, h, radius, depth);
+    }
     /// One step carve from a widget's `paint` ([`ReliefCarve`]) — offered here
     /// for the same reason as `inset_plate`: the legacy `all_quads` stream
     /// carries no relief prims, so a flat-path host never sees them.
@@ -3838,10 +3844,14 @@ pub fn render_widget<T: WidgetHost + 'static>(pc: &mut dyn RenderTarget, w: &mut
                     pending_face = Some((rect, radii, fill));
                 }
             }
-            Prim::Trough { rect, radii, depth, .. } => {
+            Prim::Trough { rect, radii, depth, tint, .. } => {
                 let face = pending_face.take().map(|(_, _, fill)| fill).unwrap_or([0.0; 4]);
                 let (r1, r2, r3, r4) = radii;
-                pc.inset_plate(face, rect.x, rect.y, rect.width, rect.height, r1.max(r2).max(r3).max(r4), depth);
+                let r = r1.max(r2).max(r3).max(r4);
+                match tint {
+                    Some(t) => pc.inset_plate_tinted(face, rect.x, rect.y, rect.width, rect.height, r, depth, t),
+                    None => pc.inset_plate(face, rect.x, rect.y, rect.width, rect.height, r, depth),
+                }
             }
             Prim::Bevel { rect, radii, color, .. } => {
                 if color[3].abs() > 0.001 {
@@ -3860,9 +3870,9 @@ pub fn render_widget<T: WidgetHost + 'static>(pc: &mut dyn RenderTarget, w: &mut
                     edges,
                 });
             }
-            Prim::Boss { rect, radii, depth, edges, .. } => {
+            Prim::Boss { rect, radii, depth, edges, tint } => {
                 pc.relief_carve(&ReliefCarve {
-                    kind: CarveKind::Boss,
+                    kind: CarveKind::Boss { tint },
                     x: rect.x,
                     y: rect.y,
                     w: rect.width,
diff --git a/src/scene/paint.rs b/src/scene/paint.rs
index b62299d..9430830 100644
--- a/src/scene/paint.rs
+++ b/src/scene/paint.rs
@@ -1066,13 +1066,7 @@ impl PaintCtx {
             PlateStance::Flush => {
                 let (trough, radii) = crate::layout::carve_inside(plate.rect, plate.radii, plate.depth);
                 match plate.tint {
-                    Some(t) => {
-                        // `inset_plate`'s face fill, then the trough with its rim lit.
-                        if plate.face[3].abs() > 0.001 {
-                            self.border(trough, radii, plate.face, [0.0; 4], 0.0);
-                        }
-                        self.trough_tinted(trough, radii, plate.depth, t);
-                    }
+                    Some(t) => self.inset_plate_tinted(trough, radii, plate.face, plate.depth, t),
                     None => self.inset_plate(trough, radii, plate.face, plate.depth),
                 }
             }
@@ -1114,6 +1108,16 @@ impl PaintCtx {
         self.trough(rect, radii, depth);
     }
 
+    /// [`inset_plate`](Self::inset_plate) with the rim lit — the focused flush
+    /// control plate's ring (`ControlPlate::with_tint`); the face fill as
+    /// there, the trough tinted.
+    pub fn inset_plate_tinted(&mut self, rect: Rect, radii: Radii, color: [f32; 4], depth: f32, tint: [f32; 3]) {
+        if color[3].abs() > 0.001 {
+            self.border(rect, radii, color, [0.0; 4], 0.0);
+        }
+        self.trough_tinted(rect, radii, depth, tint);
+    }
+
     /// Emit one [`crate::layout::ReliefCarve`]. The shared application point:
     /// a widget's `paint` carves through here, and a flat host re-emits the
     /// carves it collected through here too, so the two can only ever draw the
@@ -1126,7 +1130,10 @@ impl PaintCtx {
     pub fn carve(&mut self, c: &crate::layout::ReliefCarve) {
         let rect = Rect { x: c.x, y: c.y, width: c.w, height: c.h };
         match c.kind {
-            crate::layout::CarveKind::Boss => self.boss_edges(rect, c.radii, c.depth, c.edges),
+            crate::layout::CarveKind::Boss { tint: Some(t) } if c.edges == (true, true, true, true) => {
+                self.boss_edges_tinted(rect, c.radii, c.depth, c.edges, t)
+            }
+            crate::layout::CarveKind::Boss { .. } => self.boss_edges(rect, c.radii, c.depth, c.edges),
             crate::layout::CarveKind::Recess { tint: Some(t) }
                 if c.edges == (true, true, true, true) =>
             {
@@ -1428,6 +1435,9 @@ impl crate::layout::RenderTarget for PaintCtx {
     fn inset_plate(&mut self, color: [f32; 4], x: f32, y: f32, w: f32, h: f32, radius: f32, depth: f32) {
         PaintCtx::inset_plate(self, Rect { x, y, width: w, height: h }, (radius, radius, radius, radius), color, depth);
     }
+    fn inset_plate_tinted(&mut self, color: [f32; 4], x: f32, y: f32, w: f32, h: f32, radius: f32, depth: f32, tint: [f32; 3]) {
+        PaintCtx::inset_plate_tinted(self, Rect { x, y, width: w, height: h }, (radius, radius, radius, radius), color, depth, tint);
+    }
     fn relief_carve(&mut self, carve: &crate::layout::ReliefCarve) {
         PaintCtx::carve(self, carve);
     }
diff --git a/src/widget/container/parameters_bg.rs b/src/widget/container/parameters_bg.rs
index 5aebbed..abc7bdb 100644
--- a/src/widget/container/parameters_bg.rs
+++ b/src/widget/container/parameters_bg.rs
@@ -1193,7 +1193,7 @@ impl ParametersBg {
                         let rect = Rect { x, y: y + ty, width: w, height: h - ty };
                         for c in t.inner().flat_carves(rect) {
                             let raised = match c.kind {
-                                crate::layout::CarveKind::Boss => true,
+                                crate::layout::CarveKind::Boss { .. } => true,
                                 crate::layout::CarveKind::Recess { .. } => false,
                                 crate::layout::CarveKind::Trough => continue,
                             };
diff --git a/src/widget/input/checkbox.rs b/src/widget/input/checkbox.rs
index f36effa..07ed0db 100644
--- a/src/widget/input/checkbox.rs
+++ b/src/widget/input/checkbox.rs
@@ -376,7 +376,7 @@ impl Toggle {
         self.rocker_reliefs(inset)
             .into_iter()
             .map(|(half, radii, walls, raised)| ReliefCarve {
-                kind: if raised { CarveKind::Boss } else { CarveKind::Recess { tint: None } },
+                kind: if raised { CarveKind::Boss { tint: None } } else { CarveKind::Recess { tint: None } },
                 x: half.x,
                 y: half.y,
                 w: half.width,