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