From 70d3027bfb97bc783a124c0552879cde654ace81 Mon Sep 17 00:00:00 2001 From: Shadow Cat Date: Sun, 21 Sep 2025 17:51:10 -0400 Subject: [PATCH] move widgets out of ui --- src/layout/mod.rs | 2 + src/layout/sense.rs | 6 +-- src/layout/ui.rs | 121 +++--------------------------------------- src/layout/widgets.rs | 111 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 122 insertions(+), 118 deletions(-) create mode 100644 src/layout/widgets.rs diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 129b3b6..360cbcc 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -11,6 +11,7 @@ mod texture; mod ui; mod vec2; mod widget; +mod widgets; pub use color::*; pub use id::*; @@ -25,5 +26,6 @@ pub use texture::*; pub use ui::*; pub use vec2::*; pub use widget::*; +pub use widgets::*; pub type UiColor = Color; diff --git a/src/layout/sense.rs b/src/layout/sense.rs index c8af8f1..bed08e3 100644 --- a/src/layout/sense.rs +++ b/src/layout/sense.rs @@ -105,7 +105,7 @@ pub trait UiCtx { /// should something be done about this? pub fn run_sensors(ctx: &mut Ctx, cursor: &CursorState, window_size: Vec2) { let mut layers = std::mem::take(&mut ctx.ui().layers); - let mut map = std::mem::take(&mut ctx.ui().sensor_map); + let mut map = std::mem::take(&mut ctx.ui().event_map); // temp solution, should probably cache somewhere let mut bruh = Vec::new(); for (i, _) in layers.iter_mut() { @@ -139,10 +139,10 @@ pub fn run_sensors(ctx: &mut Ctx, cursor: &CursorState, window_size: } } let ui = ctx.ui(); - std::mem::swap(&mut ui.sensor_map, &mut map); + std::mem::swap(&mut ui.event_map, &mut map); // TODO: this removes existing sensors (if a new one is added to an id) lol // the proper code is easy but writing this comment is easier and I'm tired - ui.sensor_map.extend(map); + ui.event_map.extend(map); ui.layers = layers; } diff --git a/src/layout/ui.rs b/src/layout/ui.rs index dfea560..70c3b8d 100644 --- a/src/layout/ui.rs +++ b/src/layout/ui.rs @@ -4,9 +4,9 @@ use crate::{ core::{TextEdit, TextEditCtx}, layout::{ Layers, PainterCtx, Sensor, SensorMap, StaticWidgetId, TextData, TextureHandle, Textures, - Vec2, Widget, WidgetId, WidgetInstance, WidgetLike, + Vec2, Widget, WidgetId, WidgetInstance, WidgetLike, Widgets, }, - util::{DynBorrower, HashMap, HashSet, Id, IdTracker}, + util::{HashMap, Id}, }; use std::{ any::{Any, TypeId}, @@ -28,23 +28,7 @@ pub struct Ui { full_redraw: bool, pub(crate) active: ActiveWidgets, - pub(super) sensor_map: SensorMap, -} - -#[derive(Default)] -pub struct Widgets { - ids: IdTracker, - map: HashMap, -} - -pub struct WidgetData { - pub widget: Box, - pub label: String, - pub sized_children: HashSet, - /// dynamic borrow checking - pub borrowed: bool, - /// whether this widget has any sensors - pub sensor: bool, + pub(super) event_map: SensorMap, } impl Ui { @@ -166,7 +150,7 @@ impl Ui { /// free any resources that don't have references anymore fn free(&mut self) { for id in self.recv.try_iter() { - self.sensor_map.remove(&id); + self.event_map.remove(&id); self.widgets.delete(id); } self.textures.free(); @@ -185,7 +169,7 @@ impl Ui { } pub fn add_sensor(&mut self, id: &WidgetId, f: Sensor) { - self.sensor_map + self.event_map .entry(id.id.duplicate()) .or_default() .sensors @@ -232,99 +216,6 @@ impl IndexMut> for Ui { } } -impl Widgets { - pub fn new() -> Self { - Self { - ids: IdTracker::default(), - map: HashMap::default(), - } - } - - pub fn get_dyn(&self, id: &Id) -> Option<&dyn Widget> { - Some(self.map.get(id)?.widget.as_ref()) - } - - pub fn get_dyn_mut(&mut self, id: &Id) -> Option<&mut dyn Widget> { - Some(self.map.get_mut(id)?.widget.as_mut()) - } - - /// get_dyn but dynamic borrow checking of widgets - /// lets you do recursive (tree) operations, like the painter does - pub fn get_dyn_dynamic(&self, id: &Id) -> WidgetWrapper<'_> { - // must guarantee no other mutable references to this widget exist - // done through the borrow variable - let data: &mut WidgetData = unsafe { std::mem::transmute(self.map.get(id)) }; - if data.borrowed { - panic!("tried to mutably borrow the same widget twice"); - } - WidgetWrapper::new(data.widget.as_mut(), &mut data.borrowed) - } - - pub fn get_static(&self, id: &StaticWidgetId) -> Option<&W> { - self.get_dyn(&id.id.id())?.as_any().downcast_ref() - } - - pub fn get_static_mut(&mut self, id: &StaticWidgetId) -> Option<&mut W> { - self.get_dyn_mut(&id.id.id())?.as_any_mut().downcast_mut() - } - - pub fn get(&self, id: &WidgetId) -> Option<&W> { - self.get_dyn(&id.id)?.as_any().downcast_ref() - } - - pub fn get_mut(&mut self, id: &WidgetId) -> Option<&mut W> { - self.get_dyn_mut(&id.id)?.as_any_mut().downcast_mut() - } - - pub fn insert(&mut self, id: Id, widget: W) { - self.insert_any(id, Box::new(widget), std::any::type_name::().to_string()); - } - - pub fn data(&self, id: &Id) -> Option<&WidgetData> { - self.map.get(id) - } - - pub fn label(&self, id: &Id) -> &String { - &self.data(id).unwrap().label - } - - pub fn data_mut(&mut self, id: &Id) -> Option<&mut WidgetData> { - self.map.get_mut(id) - } - - pub fn insert_any(&mut self, id: Id, widget: Box, label: String) { - self.map.insert( - id, - WidgetData { - widget, - label, - sized_children: HashSet::default(), - borrowed: false, - sensor: false, - }, - ); - } - - pub fn delete(&mut self, id: Id) { - self.map.remove(&id); - self.ids.free(id); - } - - pub fn reserve(&mut self) -> Id { - self.ids.next() - } - - pub fn len(&self) -> usize { - self.map.len() - } - - pub fn is_empty(&self) -> bool { - self.map.is_empty() - } -} - -pub type WidgetWrapper<'a> = DynBorrower<'a, dyn Widget>; - impl dyn Widget { pub fn as_any(&self) -> &dyn Any { self @@ -347,7 +238,7 @@ impl Default for Ui { text: TextData::default(), full_redraw: false, active: Default::default(), - sensor_map: Default::default(), + event_map: Default::default(), send, recv, size: Vec2::ZERO, diff --git a/src/layout/widgets.rs b/src/layout/widgets.rs new file mode 100644 index 0000000..4539ecd --- /dev/null +++ b/src/layout/widgets.rs @@ -0,0 +1,111 @@ +use crate::{ + layout::{StaticWidgetId, Widget, WidgetId}, + util::{DynBorrower, HashMap, Id, IdTracker}, +}; + +#[derive(Default)] +pub struct Widgets { + ids: IdTracker, + map: HashMap, +} + +pub struct WidgetData { + pub widget: Box, + pub label: String, + /// dynamic borrow checking + pub borrowed: bool, + /// whether this widget has any sensors + pub sensor: bool, +} + +impl Widgets { + pub fn new() -> Self { + Self { + ids: IdTracker::default(), + map: HashMap::default(), + } + } + + pub fn get_dyn(&self, id: &Id) -> Option<&dyn Widget> { + Some(self.map.get(id)?.widget.as_ref()) + } + + pub fn get_dyn_mut(&mut self, id: &Id) -> Option<&mut dyn Widget> { + Some(self.map.get_mut(id)?.widget.as_mut()) + } + + /// get_dyn but dynamic borrow checking of widgets + /// lets you do recursive (tree) operations, like the painter does + pub fn get_dyn_dynamic(&self, id: &Id) -> WidgetWrapper<'_> { + // must guarantee no other mutable references to this widget exist + // done through the borrow variable + let data: &mut WidgetData = unsafe { std::mem::transmute(self.map.get(id)) }; + if data.borrowed { + panic!("tried to mutably borrow the same widget twice"); + } + WidgetWrapper::new(data.widget.as_mut(), &mut data.borrowed) + } + + pub fn get_static(&self, id: &StaticWidgetId) -> Option<&W> { + self.get_dyn(&id.id.id())?.as_any().downcast_ref() + } + + pub fn get_static_mut(&mut self, id: &StaticWidgetId) -> Option<&mut W> { + self.get_dyn_mut(&id.id.id())?.as_any_mut().downcast_mut() + } + + pub fn get(&self, id: &WidgetId) -> Option<&W> { + self.get_dyn(&id.id)?.as_any().downcast_ref() + } + + pub fn get_mut(&mut self, id: &WidgetId) -> Option<&mut W> { + self.get_dyn_mut(&id.id)?.as_any_mut().downcast_mut() + } + + pub fn insert(&mut self, id: Id, widget: W) { + self.insert_any(id, Box::new(widget), std::any::type_name::().to_string()); + } + + pub fn data(&self, id: &Id) -> Option<&WidgetData> { + self.map.get(id) + } + + pub fn label(&self, id: &Id) -> &String { + &self.data(id).unwrap().label + } + + pub fn data_mut(&mut self, id: &Id) -> Option<&mut WidgetData> { + self.map.get_mut(id) + } + + pub fn insert_any(&mut self, id: Id, widget: Box, label: String) { + self.map.insert( + id, + WidgetData { + widget, + label, + borrowed: false, + sensor: false, + }, + ); + } + + pub fn delete(&mut self, id: Id) { + self.map.remove(&id); + self.ids.free(id); + } + + pub fn reserve(&mut self) -> Id { + self.ids.next() + } + + pub fn len(&self) -> usize { + self.map.len() + } + + pub fn is_empty(&self) -> bool { + self.map.is_empty() + } +} + +pub type WidgetWrapper<'a> = DynBorrower<'a, dyn Widget>;