git.lucas.co / cce-gallery
widget gallery and compositor test bench

commit06cfbeb0b8a83e32d1a267ac8c3c914bf242c2e9
parent033e88ec43
authorLucas Galante <[email protected]>
date2026-09-08 10:31
fix: paint every widget prim, not only the quads

The gallery's paint loop bridged widget geometry through all_quads /
all_rounded_quads and text through the text pass, and dropped everything
else a widget paints — borders, circles, arcs, vectors. That is why the new
round Checkbox showed only its label, and, it turns out, why buttons,
toggles, sliders, spinboxes, dropdowns, the menu bar and the Ramp editor's
key handles had been drawn flat here for as long as those bridges existed.
replay_non_quad_prims runs the adapter's paint_self into a scratch context
and replays every prim but quads, rounded rects and text; the control
panel's children get the same, clipped to the panel viewport like their
quads.

Verified in a shadow session: the round Checkbox shows its ring and dot,
the Controls and Windows pages and the Ramp editor now match the toolkit's
own rendering, the panel still clips its scrolled children.

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

 src/main.rs | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/src/main.rs b/src/main.rs
index fc8eb70..c79a13b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -11,6 +11,7 @@ use gallery_widgets::{RootPlate, ControlPanel, Plate, SectionContainer};
 use cce_ui::widget::Adapted;
 use cce_ui::widget::input::Slider2D;
 use cce_ui::engine::{Vertex, quad_vertices, LogicalSize, LogicalPosition, LayerAnchor, LayerKeyboardInteractivity, LayerKind, LayerSettings};
+use cce_ui::scene::paint::Prim;
 use wayland_client::QueueHandle;
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -1885,6 +1886,11 @@ impl cce_ui::engine::Application for State {
                 for (qx, qy, qw, qh, qc) in w.all_quads(&self.ui_context) {
                     pc.quad(Rect { x: qx, y: qy, width: qw, height: qh }, qc);
                 }
+                // The quad bridges above carry only quads. A widget that paints
+                // borders, circles, arcs or vectors (the round Checkbox's ring and
+                // dot, a slider's knob, a button's border) would lose them, so
+                // replay every other own prim; text stays with the text pass.
+                replay_non_quad_prims(w, &self.ui_context, &mut pc);
             }
         }
 
@@ -1914,6 +1920,11 @@ impl cce_ui::engine::Application for State {
                         }
                     }
                 }
+                // The child's non-quad prims, clipped to the panel viewport like its quads.
+                let (px, _, pw, _) = self.roster.gallery().control_panel.rect();
+                pc.push_clip(Rect { x: px, y: y_start, width: pw, height: y_end - y_start });
+                replay_non_quad_prims(w, &self.ui_context, &mut pc);
+                pc.pop_clip();
             }
         }
 
@@ -2475,6 +2486,23 @@ impl cce_ui::engine::Application for State {
 
 }
 
+/// Re-emit a widget's own prims other than quads, rounded rects and text: the
+/// gallery's paint loop bridges quads through `all_quads`/`all_rounded_quads` and
+/// text through the text pass, and would otherwise drop a widget's borders,
+/// circles, arcs and vectors.
+fn replay_non_quad_prims(w: &(dyn WidgetHost + 'static), ui: &cce_ui::context::UiContext, pc: &mut cce_ui::scene::paint::PaintCtx) {
+    let mut scratch = cce_ui::scene::paint::PaintCtx::new();
+    w.paint_self(ui, &mut scratch);
+    for item in scratch.finish().items {
+        match item.prim {
+            Prim::Quad { .. } | Prim::RoundedRect { .. } | Prim::Text { .. } => {}
+            prim => {
+                let _ = pc.replay(prim);
+            }
+        }
+    }
+}
+
 /// A `Command` that re-runs this binary as a child window; the caller adds the flags.
 fn child_command() -> Option<std::process::Command> {
     let exe = std::env::current_exe().ok()?;