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

commit91835b818afa0ce04c297efcceef666dbf2f6450
parent44ce75ac8d
authorLucas Galante <[email protected]>
date2026-09-08 18:09
feat: exhibits follow the one label convention

The Plate exhibit drops its own label copy and paint — its label is the
adapter's detached one now, like every control's. Exhibit seeding hands
the strategy the whole block (content height plus label strip), the rect
convention cce-ui settled on, so a widget with no intrinsic height (the
Separator rule) keeps its content height instead of shrinking by a strip.
README: labels never sit inside a control's well.

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

 README.md              |  6 ++++--
 src/gallery_widgets.rs | 47 ++++++++---------------------------------------
 src/main.rs            |  4 +++-
 3 files changed, 15 insertions(+), 42 deletions(-)

diff --git a/README.md b/README.md
index 6c3534b..42f3e2f 100644
--- a/README.md
+++ b/README.md
@@ -49,8 +49,10 @@ every strategy and row builder uses in both axes), so what you see is what a
 container using that strategy does: a strategy places controls' CONTENT boxes,
 a detached label hangs in the gap above its control, mixed labeled and
 unlabeled controls line up by content (a strategy reserves the label row for
-every child of a labeled container), every detached label sits at the same
-`DETACHED_LABEL_INSET`, and every well, trough and raised plateau is carved
+every child of a labeled container), every detached label is the adapter's — the
+one label convention: drawn in the strip above the control at the same
+`DETACHED_LABEL_INSET`, never inside the control's well (no control carves a
+tab for its label; the recess is the control alone) — and every well, trough and raised plateau is carved
 inside its widget's rect (`layout::carve_inside`) so a widget's footprint is
 its rect. The exhibit
 area below the dropdown scrolls (wheel, or the scrollbar at its right edge)
diff --git a/src/gallery_widgets.rs b/src/gallery_widgets.rs
index 6ca62ae..13910b6 100644
--- a/src/gallery_widgets.rs
+++ b/src/gallery_widgets.rs
@@ -9,16 +9,15 @@ use cce_ui::scene::paint::PaintCtx;
 use cce_ui::widget::*;
 
 /// Exhibit lookalike of the old cce-ui `Plate`: config plate colour (else page colour)
-/// at plate opacity, alpha negated under blur, plate corner radius, config border, and a
-/// detached-top label with the background shifted below it.
+/// at plate opacity, alpha negated under blur, plate corner radius, config border, and the
+/// adapter's detached control label above it.
 pub struct Plate {
     blur: bool,
-    label: Option<String>,
 }
 
 impl Plate {
     pub fn new(x: f32, y: f32, w: f32, h: f32, blur: bool) -> Adapted<Plate> {
-        let mut plate = Adapted::new(Self { blur, label: None });
+        let mut plate = Adapted::new(Self { blur });
         plate.set_rect(x, y, w, h);
         plate
     }
@@ -36,27 +35,11 @@ impl Plate {
         c
     }
 
-    /// Label offset for the model-held label copy.
-    fn label_offset(&self) -> f32 {
-        if cce_ui::layout::control_label_layout() == "side" {
-            return 0.0;
-        }
-        if self.label.is_some() {
-            let (_, font_size) = cce_ui::layout::control_label_font_detached_parsed();
-            font_size + cce_ui::layout::control_label_margin()
-        } else {
-            0.0
-        }
-    }
 }
 
-impl cce_ui::widget::Layout for Plate {
-    // The rect is not inflated for the label; the background shifts below it instead
-    // (see `paint`).
-    fn inline_label(&self) -> bool {
-        true
-    }
-}
+// The label is the adapter's detached control label, in the strip above the content rect
+// `paint` fills — the one label convention every control follows.
+impl cce_ui::widget::Layout for Plate {}
 
 impl cce_ui::widget::Paint for Plate {
     fn color(&self) -> [f32; 4] {
@@ -73,27 +56,13 @@ impl cce_ui::widget::Paint for Plate {
         colors::plate_border_color().map(|bc| (bc, colors::plate_border_thickness()))
     }
 
-    fn sync_label(&mut self, label: &str) {
-        self.label = Some(label.to_string());
-    }
-
     fn paint(&self, rect: Rect, pc: &mut PaintCtx) {
-        // Rounded background below the label region, only while corners are on and the
+        // Rounded background over the content rect, only while corners are on and the
         // colour has alpha.
         let radius = cce_ui::layout::plate_corner_radius();
         let c = self.plate_color();
         if radius > 0.0 && c[3].abs() > 0.001 {
-            let label_off = self.label_offset();
-            pc.rounded_rect(
-                Rect { x: rect.x, y: rect.y + label_off, width: rect.width, height: rect.height - label_off },
-                radius,
-                (true, true, true, true),
-                c,
-            );
-        }
-        if let Some(ref label) = self.label {
-            let (_, font_size) = cce_ui::layout::control_label_font_parsed();
-            pc.text(label.clone(), rect.x, rect.y, font_size, colors::control_label_color_u8());
+            pc.rounded_rect(rect, radius, (true, true, true, true), c);
         }
     }
 }
diff --git a/src/main.rs b/src/main.rs
index 4efdf7a..befb7ce 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -935,7 +935,9 @@ impl State {
                 continue;
             }
             let widget = self.roster.get_dyn_mut(idx);
-            widget.set_rect(0.0, 0.0, cw, ch);
+            // Seed the block: the content height plus the label strip above it.
+            let strip = widget.label_strip();
+            widget.set_rect(0.0, 0.0, cw, ch + strip);
             children.push(widget as *mut (dyn WidgetHost + 'static));
             indices.push(idx);
         }