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

commit4c40c4341844b35e97a63c2eec0eca77c6faf52f
parent21dfb3990f
authorLucas Galante <[email protected]>
date2026-08-06 14:54
feat: demo + cce-bevel popovers on the direct PaintCtx path

PaintCtx is a RenderTarget — render_popover draws the real expanded
inset-plate surface; the collector flatten-and-rebound replay is gone.
Both apps expose ui_context_mut so the engine drives animation frames.

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

 src/bin/cce-bevel.rs | 24 +++++++++---------------
 src/main.rs          | 24 +++++++++---------------
 2 files changed, 18 insertions(+), 30 deletions(-)

diff --git a/src/bin/cce-bevel.rs b/src/bin/cce-bevel.rs
index b40d797..b029070 100644
--- a/src/bin/cce-bevel.rs
+++ b/src/bin/cce-bevel.rs
@@ -735,21 +735,10 @@ impl Application for BevelPopup {
 
         // The selector's popover, drawn into the frame on top of everything
         // below it (its labels carry the popover rect as bounds).
-        if let Some((px, py, pw, ph)) = self.profile_dropdown.popover_rect() {
-            let mut coll = cce_ui::layout::PopoverCollector::new();
-            self.profile_dropdown.render_popover(&mut coll);
-            for &(c, x, y, qw, qh) in &coll.rects {
-                pc.quad(Rect { x, y, width: qw, height: qh }, c);
-            }
-            let bounds = Some([px, py, px + pw, py + ph]);
-            for (content, size, tx, ty, color, font, _b) in coll.texts {
-                let color_u8 = [
-                    (color[0] * 255.0).clamp(0.0, 255.0) as u8,
-                    (color[1] * 255.0).clamp(0.0, 255.0) as u8,
-                    (color[2] * 255.0).clamp(0.0, 255.0) as u8,
-                ];
-                pc.text_with(content, tx, ty, size, color_u8, font, bounds);
-            }
+        if self.profile_dropdown.popover_rect().is_some() {
+            // PaintCtx is a RenderTarget: the popover draws its real prims (the
+            // dropdown's expanded inset-plate surface) with its own bounds.
+            self.profile_dropdown.render_popover(&mut pc);
         }
 
         // The shared context menu (slider Copy/Paste), last, on top.
@@ -780,6 +769,11 @@ impl Application for BevelPopup {
         Some(&self.ui_context)
     }
 
+    // Engine-driven animation frames for the dropdown expand/contract.
+    fn ui_context_mut(&mut self) -> Option<&mut cce_ui::context::UiContext> {
+        Some(&mut self.ui_context)
+    }
+
     fn is_movable_backplate_at(&self, px: f32, py: f32) -> bool {
         self.ui_context.drag_allowed_at(px, py)
     }
diff --git a/src/main.rs b/src/main.rs
index d1e87da..f0fd643 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -433,21 +433,10 @@ impl Application for DemoApp {
         // where it hit-tests. Labels carry bounds equal to the popover rect: that clips
         // them to the plate AND exempts them from the occlusion clamp (text whose bounds
         // equal an overlay rect is treated as the overlay's own).
-        if let Some((px, py, pw, ph)) = self.theme_dropdown.popover_rect() {
-            let mut coll = cce_ui::layout::PopoverCollector::new();
-            self.theme_dropdown.render_popover(&mut coll);
-            for &(c, x, y, qw, qh) in &coll.rects {
-                pc.quad(Rect { x, y, width: qw, height: qh }, c);
-            }
-            let bounds = Some([px, py, px + pw, py + ph]);
-            for (content, size, tx, ty, color, font, _b) in coll.texts {
-                let color_u8 = [
-                    (color[0] * 255.0).clamp(0.0, 255.0) as u8,
-                    (color[1] * 255.0).clamp(0.0, 255.0) as u8,
-                    (color[2] * 255.0).clamp(0.0, 255.0) as u8,
-                ];
-                pc.text_with(content, tx, ty, size, color_u8, font, bounds);
-            }
+        if self.theme_dropdown.popover_rect().is_some() {
+            // PaintCtx is a RenderTarget: the popover draws its real prims (the
+            // dropdown's expanded inset-plate surface) with its own bounds.
+            self.theme_dropdown.render_popover(&mut pc);
         }
 
         Some(pc.finish())
@@ -462,6 +451,11 @@ impl Application for DemoApp {
         Some(&self.ui_context)
     }
 
+    // Engine-driven animation frames for the dropdown expand/contract.
+    fn ui_context_mut(&mut self) -> Option<&mut cce_ui::context::UiContext> {
+        Some(&mut self.ui_context)
+    }
+
     /// Window dragging for a dissolved root: the surface is the movable plate; drag
     /// anywhere a drag-blocking registered widget isn't.
     fn is_movable_backplate_at(&self, px: f32, py: f32) -> bool {