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

commit4f51857bbcf2da243a000536a2f703f966008495
parent924741d73d
authorLucas Galante <[email protected]>
date2026-07-13 08:38
refactor: roster value drains go concrete-slot (6bd value shrink)

The WidgetHost polling block is gone; Roster grew take_click/value/
get_value_string/set_text(idx) matches routing each drained gallery index
to its concrete slot's inherent Adapted method (unwired slots panic loudly).

Verified live: Button/Toggle clicks, Layout dropdown popover, Grid
selection re-lays out the gallery through the new drains.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01N4ajhvVZtyEEEus9bodsj3

 src/main.rs | 175 ++++++++++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 128 insertions(+), 47 deletions(-)

diff --git a/src/main.rs b/src/main.rs
index 261fde4..6cb799a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -324,6 +324,87 @@ impl Roster {
             Roster::Child(_) => panic!("gallery slots requested in child mode"),
         }
     }
+
+    // --- App-local value drains (6bd value shrink): the `WidgetHost` polling block
+    // (`take_click`/`value`/`get_value_string`/`set_text`) went concrete-slot — these
+    // route a gallery index to its concrete slot's inherent `Adapted` method. Arms exist
+    // only for the slots the page logic actually drains; a new drain site adds its arm.
+
+    pub fn take_click(&mut self, idx: usize) -> bool {
+        let s = self.gallery_mut();
+        match idx {
+            2 => s.status_bar.take_click(),
+            3 => s.button_demo.take_click(),
+            9 => s.checkbox_demo.take_click(),
+            10 => s.toggle_demo.take_click(),
+            12 => s.slider_demo.take_click(),
+            13 => s.spinbox_demo.take_click(),
+            15 => s.create_window_btn.take_click(),
+            16 => s.tile_windows_btn.take_click(),
+            17 => s.opacity_toggle.take_click(),
+            19 => s.transparency_slider.take_click(),
+            21 => s.window_type_dd.take_click(),
+            22 => s.window_shape_dd.take_click(),
+            23 => s.enable_toggle.take_click(),
+            25 => s.width_spin.take_click(),
+            26 => s.height_spin.take_click(),
+            30 => s.range_slider_demo.take_click(),
+            31 => s.trackpad_demo.take_click(),
+            34 => s.open_dialog_btn.take_click(),
+            35 => s.save_dialog_btn.take_click(),
+            36 => s.textbox_demo.take_click(),
+            37 => s.plate_demo.take_click(),
+            38 => s.backplate_toggle.take_click(),
+            39 => s.menubar_toggle.take_click(),
+            40 => s.statusbar_toggle.take_click(),
+            42 => s.bevel_toggle.take_click(),
+            43 => s.border_width_spin.take_click(),
+            44 => s.bevel_depth_spin.take_click(),
+            46 => s.page_selector.take_click(),
+            47 => s.color_ramp_btn.take_click(),
+            48 => s.bevel_shape_btn.take_click(),
+            50 => s.ramp_btn.take_click(),
+            52 => s.layout_dd.take_click(),
+            _ => panic!("take_click: unwired gallery slot {idx}"),
+        }
+    }
+
+    pub fn value(&self, idx: usize) -> i32 {
+        let s = self.gallery();
+        match idx {
+            19 => s.transparency_slider.value(),
+            21 => s.window_type_dd.value(),
+            22 => s.window_shape_dd.value(),
+            25 => s.width_spin.value(),
+            26 => s.height_spin.value(),
+            43 => s.border_width_spin.value(),
+            44 => s.bevel_depth_spin.value(),
+            46 => s.page_selector.value(),
+            52 => s.layout_dd.value(),
+            _ => panic!("value: unwired gallery slot {idx}"),
+        }
+    }
+
+    pub fn get_value_string(&self, idx: usize) -> Option<String> {
+        let s = self.gallery();
+        match idx {
+            17 => s.opacity_toggle.get_value_string(),
+            23 => s.enable_toggle.get_value_string(),
+            38 => s.backplate_toggle.get_value_string(),
+            39 => s.menubar_toggle.get_value_string(),
+            40 => s.statusbar_toggle.get_value_string(),
+            42 => s.bevel_toggle.get_value_string(),
+            _ => panic!("get_value_string: unwired gallery slot {idx}"),
+        }
+    }
+
+    pub fn set_text(&mut self, idx: usize, text: &str) {
+        let s = self.gallery_mut();
+        match idx {
+            29 => s.surface_desc_label.set_text(text),
+            _ => panic!("set_text: unwired gallery slot {idx}"),
+        }
+    }
 }
 
 struct State {
@@ -1096,10 +1177,10 @@ cascades in cce."
             }
             if !self.is_child && i == 14 {
                 let r = cce_ui::color::backplate_corner_radius();
-                let backplate_enabled = self.roster.get_dyn(38).get_value_string() == Some("true".to_string());
-                let border_bevel = self.roster.get_dyn(42).get_value_string() == Some("true".to_string());
-                let opacity_enabled = self.roster.get_dyn(17).get_value_string() == Some("true".to_string());
-                let transparency_val = if opacity_enabled { self.roster.get_dyn(19).value() as f32 / 100.0 } else { 1.0 };
+                let backplate_enabled = self.roster.get_value_string(38) == Some("true".to_string());
+                let border_bevel = self.roster.get_value_string(42) == Some("true".to_string());
+                let opacity_enabled = self.roster.get_value_string(17) == Some("true".to_string());
+                let transparency_val = if opacity_enabled { self.roster.value(19) as f32 / 100.0 } else { 1.0 };
                 let bg_color = if backplate_enabled {
                     let mut col = cce_ui::color::page_low_color();
                     col[3] = transparency_val;
@@ -1111,7 +1192,7 @@ cascades in cce."
                 let (wx, wy, ww, wh) = w.rect();
                 if backplate_enabled {
                     if border_bevel {
-                        let t = self.roster.get_dyn(43).value() as f32;
+                        let t = self.roster.value(43) as f32;
                         let r_inner = (r - t).max(0.0);
                         push_rounded(&mut pc, wx + t, wy + t, ww - 2.0 * t, wh - 2.0 * t, r_inner, bg_color, (true, true, true, true));
                     } else {
@@ -1119,7 +1200,7 @@ cascades in cce."
                     }
                 }
 
-                let menubar_enabled = self.roster.get_dyn(39).get_value_string() == Some("true".to_string());
+                let menubar_enabled = self.roster.get_value_string(39) == Some("true".to_string());
                 if menubar_enabled {
                     let mut menu_color = cce_ui::color::backplate_menubar_color();
                     menu_color[3] = transparency_val;
@@ -1130,7 +1211,7 @@ cascades in cce."
                     }
                 }
 
-                let statusbar_enabled = self.roster.get_dyn(40).get_value_string() == Some("true".to_string());
+                let statusbar_enabled = self.roster.get_value_string(40) == Some("true".to_string());
                 if statusbar_enabled {
                     let mut status_color = cce_ui::color::backplate_statusbar_color();
                     status_color[3] = transparency_val;
@@ -1166,9 +1247,9 @@ cascades in cce."
                 continue;
             }
             if !self.is_child && i == 14 {
-                let backplate_enabled = self.roster.get_dyn(38).get_value_string() == Some("true".to_string());
-                let opacity_enabled = self.roster.get_dyn(17).get_value_string() == Some("true".to_string());
-                let transparency_val = if opacity_enabled { self.roster.get_dyn(19).value() as f32 / 100.0 } else { 1.0 };
+                let backplate_enabled = self.roster.get_value_string(38) == Some("true".to_string());
+                let opacity_enabled = self.roster.get_value_string(17) == Some("true".to_string());
+                let transparency_val = if opacity_enabled { self.roster.value(19) as f32 / 100.0 } else { 1.0 };
                 let bg_color = if backplate_enabled {
                     let mut col = cce_ui::color::page_low_color();
                     col[3] = transparency_val;
@@ -1340,11 +1421,11 @@ cascades in cce."
             }
 
             if !self.is_child && i == 14 {
-                let border_enabled = self.roster.get_dyn(23).get_value_string() == Some("true".to_string());
+                let border_enabled = self.roster.get_value_string(23) == Some("true".to_string());
                 if border_enabled {
-                    let backplate_enabled = self.roster.get_dyn(38).get_value_string() == Some("true".to_string());
-                    let opacity_enabled = self.roster.get_dyn(17).get_value_string() == Some("true".to_string());
-                    let transparency_val = if opacity_enabled { self.roster.get_dyn(19).value() as f32 / 100.0 } else { 1.0 };
+                    let backplate_enabled = self.roster.get_value_string(38) == Some("true".to_string());
+                    let opacity_enabled = self.roster.get_value_string(17) == Some("true".to_string());
+                    let transparency_val = if opacity_enabled { self.roster.value(19) as f32 / 100.0 } else { 1.0 };
                     let bg_color = if backplate_enabled {
                         let mut col = cce_ui::color::page_low_color();
                         col[3] = transparency_val;
@@ -1355,8 +1436,8 @@ cascades in cce."
 
                     let mut border_color = cce_ui::color::plate_border_color().unwrap_or([0.3, 0.3, 0.4, 1.0]);
                     border_color[3] = transparency_val;
-                    let t = self.roster.get_dyn(43).value() as f32;
-                    let border_bevel = self.roster.get_dyn(42).get_value_string() == Some("true".to_string());
+                    let t = self.roster.value(43) as f32;
+                    let border_bevel = self.roster.get_value_string(42) == Some("true".to_string());
                     let r = cce_ui::color::backplate_corner_radius();
                     let (wx, wy, ww, wh) = w.rect();
                     
@@ -1373,7 +1454,7 @@ cascades in cce."
                                 let h_inner = interpolate_ramp_value(&self.bevel_ramp, u_next, &self.bevel_ramp_line_type);
                                 
                                 let d_h = h_inner - h_outer;
-                                let bevel_depth = self.roster.get_dyn(44).value() as f32 / 100.0;
+                                let bevel_depth = self.roster.value(44) as f32 / 100.0;
                                 let color_offset = d_h * bevel_depth * 2.667;
                                 
                                  let rad = cce_ui::layout::light_source_position();
@@ -1597,14 +1678,14 @@ cascades in cce."
 
             if button == MouseButton::Left {
                 if self.is_child {
-                    if self.roster.get_dyn_mut(2).take_click() {
+                    if self.roster.take_click(2) {
                         return Some("exit".to_string());
                     }
                 } else {
                     let mut page_changed = false;
                     let mut selected = 0;
-                    if self.roster.get_dyn_mut(46).take_click() {
-                        selected = self.roster.get_dyn(46).value();
+                    if self.roster.take_click(46) {
+                        selected = self.roster.value(46);
                         page_changed = true;
                     }
                     
@@ -1621,15 +1702,15 @@ cascades in cce."
                         }
                         self.apply_layout();
                         changed = true;
-                    } else if self.roster.get_dyn_mut(52).take_click() {
-                        self.layout_idx = self.roster.get_dyn(52).value() as usize;
+                    } else if self.roster.take_click(52) {
+                        self.layout_idx = self.roster.value(52) as usize;
                         self.positions = demo_positions(self.width, self.height, cce_ui::widget::PageSelector::sidebar_w(self.roster.gallery().paginator.as_any().downcast_ref::<cce_ui::widget::Paginator>().expect("slot 1 must be the Paginator")), self.layout_idx, self.roster.gallery());
                         self.apply_layout();
                         changed = true;
                     } else if self.current_page == Page::Controls {
-                        if self.roster.get_dyn_mut(3).take_click() {
+                        if self.roster.take_click(3) {
                             // Does nothing
-                        } else if self.roster.get_dyn_mut(47).take_click() {
+                        } else if self.roster.take_click(47) {
                             if let Ok(exe) = std::env::current_exe() {
                                 let mut cmd = std::process::Command::new(exe);
                                 cmd.arg("--child")
@@ -1642,7 +1723,7 @@ cascades in cce."
                                    .arg("--backplate");
                                 let _ = cmd.spawn();
                             }
-                        } else if self.roster.get_dyn_mut(50).take_click() {
+                        } else if self.roster.take_click(50) {
                             if let Ok(exe) = std::env::current_exe() {
                                 let mut cmd = std::process::Command::new(exe);
                                 cmd.arg("--child")
@@ -1657,7 +1738,7 @@ cascades in cce."
                             }
                         } else {
                             for i in [9, 10, 12, 13, 30, 31, 36, 37] {
-                                if self.roster.get_dyn_mut(i).take_click() {
+                                if self.roster.take_click(i) {
                                     changed = true;
                                 }
                             }
@@ -1666,11 +1747,11 @@ cascades in cce."
                         let mut create_window = false;
                         let mut tile_windows = false;
                         
-                        if self.roster.get_dyn_mut(15).take_click() {
+                        if self.roster.take_click(15) {
                             create_window = true;
-                        } else if self.roster.get_dyn_mut(16).take_click() {
+                        } else if self.roster.take_click(16) {
                             tile_windows = true;
-                        } else if self.roster.get_dyn_mut(48).take_click() {
+                        } else if self.roster.take_click(48) {
                             if let Ok(exe) = std::env::current_exe() {
                                 let mut cmd = std::process::Command::new(exe);
                                 cmd.arg("--child")
@@ -1686,13 +1767,13 @@ cascades in cce."
                         } else {
                             let mut dropdown_clicked = false;
                             for i in [17, 19, 21, 22, 23, 25, 26, 38, 39, 40, 42, 43, 44] {
-                                if self.roster.get_dyn_mut(i).take_click() {
+                                if self.roster.take_click(i) {
                                     changed = true;
                                     if i == 21 {
                                         dropdown_clicked = true;
                                     }
                                     if i == 44 {
-                                        let depth = self.roster.get_dyn(44).value() as f32 / 100.0;
+                                        let depth = self.roster.value(44) as f32 / 100.0;
                                         if let Ok(mut registry) = cce_ui::layout::get_style_registry().write() {
                                             registry.set_float("bevel_depth", depth);
                                         }
@@ -1700,7 +1781,7 @@ cascades in cce."
                                 }
                             }
                             if dropdown_clicked {
-                                let desc = match self.roster.get_dyn(21).value() {
+                                let desc = match self.roster.value(21) {
                                     0 => "A standard application\n\
 window (xdg_toplevel).\n\
 It supports tiling (cascade,\n\
@@ -1738,12 +1819,12 @@ Testing layout:\n\
 full screen background.",
                                     _ => "",
                                 };
-                                self.roster.get_dyn_mut(29).set_text(desc);
+                                self.roster.set_text(29, desc);
                             }
                         }
                         
                         if create_window {
-                            let window_type = match self.roster.get_dyn(21).value() {
+                            let window_type = match self.roster.value(21) {
                                 0 => "Toplevel",
                                 1 => "Popup",
                                 2 => "LayerTop",
@@ -1751,17 +1832,17 @@ full screen background.",
                                 4 => "LayerBackground",
                                 _ => "Toplevel",
                             };
-                            let shape = match self.roster.get_dyn(22).value() {
+                            let shape = match self.roster.value(22) {
                                 0 => "rectangular",
                                 1 => "circular",
                                 _ => "rectangular",
                             };
-                            let opacity_enabled = self.roster.get_dyn(17).get_value_string() == Some("true".to_string());
-                            let transparency_pct = self.roster.get_dyn(19).value();
+                            let opacity_enabled = self.roster.get_value_string(17) == Some("true".to_string());
+                            let transparency_pct = self.roster.value(19);
                             let transparency_val = transparency_pct as f32 / 100.0;
-                            let border_enabled = self.roster.get_dyn(23).get_value_string() == Some("true".to_string());
-                            let custom_width = self.roster.get_dyn(25).value();
-                            let custom_height = self.roster.get_dyn(26).value();
+                            let border_enabled = self.roster.get_value_string(23) == Some("true".to_string());
+                            let custom_width = self.roster.value(25);
+                            let custom_height = self.roster.value(26);
      
                             self.update_status_text(&format!("Spawning simulated {} {} window...", shape, window_type));
                             if let Ok(exe) = std::env::current_exe() {
@@ -1771,9 +1852,9 @@ full screen background.",
                                    .arg(window_type)
                                    .arg("--shape")
                                    .arg(shape);
-                                let backplate_enabled = self.roster.get_dyn(38).get_value_string() == Some("true".to_string());
-                                let menubar_enabled = self.roster.get_dyn(39).get_value_string() == Some("true".to_string());
-                                let statusbar_enabled = self.roster.get_dyn(40).get_value_string() == Some("true".to_string());
+                                let backplate_enabled = self.roster.get_value_string(38) == Some("true".to_string());
+                                let menubar_enabled = self.roster.get_value_string(39) == Some("true".to_string());
+                                let statusbar_enabled = self.roster.get_value_string(40) == Some("true".to_string());
                                 if opacity_enabled {
                                     cmd.arg("--opacity")
                                        .arg("--transparency")
@@ -1782,8 +1863,8 @@ full screen background.",
                                 if !border_enabled {
                                     cmd.arg("--no-border");
                                 } else {
-                                    let border_width = self.roster.get_dyn(43).value() as f32;
-                                    let border_bevel = self.roster.get_dyn(42).get_value_string() == Some("true".to_string());
+                                    let border_width = self.roster.value(43) as f32;
+                                    let border_bevel = self.roster.get_value_string(42) == Some("true".to_string());
                                     cmd.arg("--border-width")
                                        .arg(border_width.to_string());
                                     if border_bevel {
@@ -1813,9 +1894,9 @@ full screen background.",
                     } else if self.current_page == Page::Xdg {
                         let mut open_file = false;
                         let mut save_file = false;
-                        if self.roster.get_dyn_mut(34).take_click() {
+                        if self.roster.take_click(34) {
                             open_file = true;
-                        } else if self.roster.get_dyn_mut(35).take_click() {
+                        } else if self.roster.take_click(35) {
                             save_file = true;
                         }