use crate::{ layout::{IdLike, Widget}, 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, } 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<'_> { // SAFETY: must guarantee no other mutable references to this widget exist // done through the borrow variable #[allow(mutable_transmutes)] let data = unsafe { std::mem::transmute::<&WidgetData, &mut WidgetData>(self.map.get(&id).unwrap()) }; if data.borrowed { panic!("tried to mutably borrow the same widget twice"); } WidgetWrapper::new(data.widget.as_mut(), &mut data.borrowed) } pub fn get(&self, id: &impl IdLike) -> Option<&W> { self.get_dyn(id.id())?.as_any().downcast_ref() } pub fn get_mut(&mut self, id: &impl IdLike) -> Option<&mut W> { self.get_dyn_mut(id.id())?.as_any_mut().downcast_mut() } pub fn insert(&mut self, id: Id, widget: W) { let mut label = std::any::type_name::().to_string(); if let (Some(first), Some(last)) = (label.find(":"), label.rfind(":")) { label = label.split_at(first).0.to_string() + "::" + label.split_at(last + 1).1; } self.insert_any(id, Box::new(widget), label); } 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, }, ); } 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>;