git.lucas.co / cce-system-interface
system settings
git clone https://git.lucas.co/cce-system-interface.git

commit83c8f8187e6f5123fabc0e957b9c9e1c762c39ea
parent9612548fe5
authorLucas Galante <lsgalante12@gmail.com>
date2026-10-09 00:54
refactor: read the registry through get_widget and widgets()

cce-ui's registry owns its widgets (owning registry, phase 5); its raw-pointer tree accessors are crate-private. The focused-text-box check, the refocus rect, popover paint and the focus heir's search use the safe accessors.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

 src/input_handler.rs | 12 +++++-------
 src/renderer.rs      | 22 ++++++++--------------
 2 files changed, 13 insertions(+), 21 deletions(-)

diff --git a/src/input_handler.rs b/src/input_handler.rs
index 66b36cd..dfa6682 100644
--- a/src/input_handler.rs
+++ b/src/input_handler.rs
@@ -515,13 +515,11 @@ impl SystemInterface {
             }
         }
 
-        let is_text_box_focused = if let Some(focused) =
-            self.ui_context.focused_widget.and_then(|id| self.ui_context.tree.get_ptr(id))
-        {
-            unsafe { (*focused).as_any().is::<cce_ui::widget::input::TextBox>() }
-        } else {
-            false
-        };
+        let is_text_box_focused = self
+            .ui_context
+            .focused_widget
+            .and_then(|id| self.ui_context.get_widget(id))
+            .is_some_and(|focused| focused.as_any().is::<cce_ui::widget::input::TextBox>());
 
         if !self.search_open && !is_text_box_focused {
             if event.state == cce_ui::widget::ElementState::Pressed && !event.repeat {
diff --git a/src/renderer.rs b/src/renderer.rs
index 28fe205..a099e05 100644
--- a/src/renderer.rs
+++ b/src/renderer.rs
@@ -28,8 +28,8 @@ impl SystemInterface {
         self.refocus_rect = self
             .ui_context
             .focused_widget
-            .and_then(|id| self.ui_context.tree.get_ptr(id))
-            .map(|ptr| unsafe { (*ptr).rect() });
+            .and_then(|id| self.ui_context.get_widget(id))
+            .map(|w| w.rect());
         // SectionContainer dissolved (Phase 6w): no per-rebuild section clones to
         // relink — the page's widgets dispatch directly (registration happens in
         // render_widget during the view pass below).
@@ -592,13 +592,11 @@ impl SystemInterface {
             let chrome_id = self.page_dropdown.id();
             let mut page_pop_pc = PageContent::new();
             for &pop_id in &self.ui_context.active_popovers {
-                let Some(pop_ptr) = self.ui_context.tree.get_ptr(pop_id) else { continue };
-                unsafe {
-                    if pop_id == chrome_id {
-                        (*pop_ptr).render_popover(&mut popover_pc);
-                    } else {
-                        (*pop_ptr).render_popover(&mut page_pop_pc);
-                    }
+                let Some(popover) = self.ui_context.get_widget(pop_id) else { continue };
+                if pop_id == chrome_id {
+                    popover.render_popover(&mut popover_pc);
+                } else {
+                    popover.render_popover(&mut page_pop_pc);
                 }
             }
             // The chrome popover's rects are already in place: the page
@@ -658,11 +656,7 @@ impl SystemInterface {
         // page buttons above are per-rebuild allocations; see `focus_stepped`).
         if let Some((fx, fy, fw, fh)) = self.refocus_rect.take() {
             let near = |a: f32, b: f32| (a - b).abs() < 0.5;
-            let heir = self.ui_context.tree.iter_registered().find_map(|(id, ptr)| {
-                if ptr.is_null() {
-                    return None;
-                }
-                let w = unsafe { &*ptr };
+            let heir = self.ui_context.widgets().find_map(|(id, w)| {
                 let (x, y, ww, hh) = w.rect();
                 (w.focus_role() != cce_ui::widget::FocusRole::None && near(x, fx) && near(y, fy) && near(ww, fw) && near(hh, fh))
                     .then_some(id)