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

commitab80e3c9f49c4be8476c70b257cbbffa9d591239
parent6428d50534
authorLucas Galante <[email protected]>
date2026-07-05 02:02
Refactor layouts to use localized state instead of global thread-local statics

 src/layout.rs                            | 20 ----------
 src/widget/container/container_layout.rs | 63 ++++++++++++++++----------------
 2 files changed, 31 insertions(+), 52 deletions(-)

diff --git a/src/layout.rs b/src/layout.rs
index 8a13f63..f59f3ba 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -4282,27 +4282,7 @@ impl Radial {
     }
 }
 
-use std::cell::RefCell;
 
-thread_local! {
-    pub static GRID_STATES: RefCell<HashMap<usize, Grid>> = RefCell::new(HashMap::new());
-    pub static OVERLAY_STATES: RefCell<HashMap<usize, (f32, f32, f32, f32)>> = RefCell::new(HashMap::new());
-    pub static VERTICAL_STATES: RefCell<HashMap<usize, (f32, f32)>> = RefCell::new(HashMap::new());
-}
-
-pub fn save_grid_state(ptr: usize, grid: Grid) {
-    GRID_STATES.with(|m| m.borrow_mut().insert(ptr, grid));
-}
-
-pub fn mutate_grid_state<F, R>(ptr: usize, mut f: F) -> Option<R>
-where
-    F: FnMut(&mut Grid) -> R,
-{
-    GRID_STATES.with(|m| {
-        let mut map = m.borrow_mut();
-        map.get_mut(&ptr).map(|grid| f(grid))
-    })
-}
 
 pub trait LayoutStrategy: std::fmt::Debug {
     fn init(&mut self, left: f32, top: f32, width: f32, height: f32);
diff --git a/src/widget/container/container_layout.rs b/src/widget/container/container_layout.rs
index 88c0df0..428a704 100644
--- a/src/widget/container/container_layout.rs
+++ b/src/widget/container/container_layout.rs
@@ -72,6 +72,8 @@ pub struct VerticalLayout {
     pub padding_x: f32,
     pub padding_y: f32,
     pub spacing: f32,
+    left: f32,
+    current_y: f32,
 }
 
 impl Default for VerticalLayout {
@@ -80,23 +82,22 @@ impl Default for VerticalLayout {
             padding_x: 0.0,
             padding_y: 0.0,
             spacing: 8.0,
+            left: 0.0,
+            current_y: 0.0,
         }
     }
 }
 
 impl crate::layout::LayoutStrategy for VerticalLayout {
     fn init(&mut self, left: f32, top: f32, _width: f32, _height: f32) {
-        let ptr = self as *const Self as usize;
-        crate::layout::VERTICAL_STATES.with(|m| m.borrow_mut().insert(ptr, (left, top + self.padding_y)));
+        self.left = left;
+        self.current_y = top + self.padding_y;
     }
 
     fn allocate(&mut self, ww: f32, wh: f32) -> (f32, f32, f32, f32) {
-        let ptr = self as *const Self as usize;
-        let (left, mut current_y) = crate::layout::VERTICAL_STATES.with(|m| m.borrow().get(&ptr).copied().unwrap_or((0.0, 0.0)));
-        let x = left + self.padding_x;
-        let y = current_y;
-        current_y += wh + self.spacing;
-        crate::layout::VERTICAL_STATES.with(|m| m.borrow_mut().insert(ptr, (left, current_y)));
+        let x = self.left + self.padding_x;
+        let y = self.current_y;
+        self.current_y += wh + self.spacing;
         (x, y, ww, wh)
     }
 
@@ -154,12 +155,13 @@ impl ContainerLayout for VerticalLayout {
     }
 }
 
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone)]
 pub struct GridLayout {
     pub columns: usize,
     pub gap: f32,
     pub padding_x: f32,
     pub padding_y: f32,
+    pub grid: Option<crate::layout::Grid>,
 }
 
 impl crate::layout::LayoutStrategy for GridLayout {
@@ -174,26 +176,23 @@ impl crate::layout::LayoutStrategy for GridLayout {
             self.gap,
             count,
         );
-        let ptr = self as *const Self as usize;
-        crate::layout::save_grid_state(ptr, grid);
+        self.grid = Some(grid);
     }
 
     fn allocate(&mut self, ww: f32, wh: f32) -> (f32, f32, f32, f32) {
-        let ptr = self as *const Self as usize;
-        crate::layout::mutate_grid_state(ptr, |grid| {
+        if let Some(ref mut grid) = self.grid {
             let col = grid.next_column();
             let x = grid.col_lefts[col];
             let y = grid.col_heights[col];
             grid.col_heights[col] += wh + grid.gap;
             (x, y, grid.col_width, wh)
-        }).unwrap_or((0.0, 0.0, ww, wh))
+        } else {
+            (0.0, 0.0, ww, wh)
+        }
     }
 
     fn get_column_width(&self) -> Option<f32> {
-        let ptr = self as *const Self as usize;
-        crate::layout::GRID_STATES.with(|m| {
-            m.borrow().get(&ptr).map(|g| g.col_width)
-        })
+        self.grid.as_ref().map(|g| g.col_width)
     }
 
     fn get_gap(&self) -> f32 {
@@ -270,22 +269,23 @@ impl crate::layout::LayoutStrategy for GridLayout {
     }
 
     fn box_clone(&self) -> Box<dyn crate::layout::LayoutStrategy> {
-        Box::new(*self)
+        Box::new(self.clone())
     }
 }
 
 impl ContainerLayout for GridLayout {
     fn box_clone_container(&self) -> Box<dyn ContainerLayout> {
-        Box::new(*self)
+        Box::new(self.clone())
     }
 }
 
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone)]
 pub struct AdaptiveGridLayout {
     pub min_col_width: f32,
     pub gap: f32,
     pub padding_x: f32,
     pub padding_y: f32,
+    pub grid: Option<crate::layout::Grid>,
 }
 
 impl crate::layout::LayoutStrategy for AdaptiveGridLayout {
@@ -300,26 +300,23 @@ impl crate::layout::LayoutStrategy for AdaptiveGridLayout {
             self.gap,
             cols,
         );
-        let ptr = self as *const Self as usize;
-        crate::layout::save_grid_state(ptr, grid);
+        self.grid = Some(grid);
     }
 
     fn allocate(&mut self, ww: f32, wh: f32) -> (f32, f32, f32, f32) {
-        let ptr = self as *const Self as usize;
-        crate::layout::mutate_grid_state(ptr, |grid| {
+        if let Some(ref mut grid) = self.grid {
             let col = grid.next_column();
             let x = grid.col_lefts[col];
             let y = grid.col_heights[col];
             grid.col_heights[col] += wh + grid.gap;
             (x, y, grid.col_width, wh)
-        }).unwrap_or((0.0, 0.0, ww, wh))
+        } else {
+            (0.0, 0.0, ww, wh)
+        }
     }
 
     fn get_column_width(&self) -> Option<f32> {
-        let ptr = self as *const Self as usize;
-        crate::layout::GRID_STATES.with(|m| {
-            m.borrow().get(&ptr).map(|g| g.col_width)
-        })
+        self.grid.as_ref().map(|g| g.col_width)
     }
 
     fn get_gap(&self) -> f32 {
@@ -334,6 +331,7 @@ impl crate::layout::LayoutStrategy for AdaptiveGridLayout {
             gap: self.gap,
             padding_x: self.padding_x,
             padding_y: self.padding_y,
+            grid: None,
         };
         grid.layout(x, y, w, h, children, ctx)
     }
@@ -346,17 +344,18 @@ impl crate::layout::LayoutStrategy for AdaptiveGridLayout {
             gap: self.gap,
             padding_x: self.padding_x,
             padding_y: self.padding_y,
+            grid: None,
         };
         grid.measure(constraints, children, ctx)
     }
 
     fn box_clone(&self) -> Box<dyn crate::layout::LayoutStrategy> {
-        Box::new(*self)
+        Box::new(self.clone())
     }
 }
 
 impl ContainerLayout for AdaptiveGridLayout {
     fn box_clone_container(&self) -> Box<dyn ContainerLayout> {
-        Box::new(*self)
+        Box::new(self.clone())
     }
 }