use crate::{ IdLike, Widget, WidgetId, util::{DynBorrower, HashSet, SlotVec}, }; #[derive(Default)] pub struct Widgets { pub updates: HashSet, vec: SlotVec, } pub struct WidgetData { pub widget: Box, pub label: String, /// dynamic borrow checking pub borrowed: bool, } impl Widgets { pub fn has_updates(&self) -> bool { !self.updates.is_empty() } pub fn get_dyn(&self, id: WidgetId) -> Option<&dyn Widget> { Some(self.vec.get(id)?.widget.as_ref()) } pub fn get_dyn_mut(&mut self, id: WidgetId) -> Option<&mut dyn Widget> { self.updates.insert(id); Some(self.vec.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: WidgetId) -> 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.vec.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: &I) -> Option<&I::Widget> where I::Widget: Sized, { self.get_dyn(id.id())?.as_any().downcast_ref() } pub fn get_mut(&mut self, id: &I) -> Option<&mut I::Widget> where I::Widget: Sized, { self.get_dyn_mut(id.id())?.as_any_mut().downcast_mut() } pub fn add(&mut self, widget: W) -> WidgetId { 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(Box::new(widget), label) } pub fn data(&self, id: WidgetId) -> Option<&WidgetData> { self.vec.get(id) } pub fn label(&self, id: WidgetId) -> &String { &self.data(id).unwrap().label } pub fn data_mut(&mut self, id: WidgetId) -> Option<&mut WidgetData> { self.vec.get_mut(id) } pub fn insert_any(&mut self, widget: Box, label: String) -> WidgetId { self.vec.add(WidgetData { widget, label, borrowed: false, }) } pub fn delete(&mut self, id: WidgetId) { self.vec.free(id); // not sure if there's any point in this // self.updates.remove(&id); } #[allow(clippy::len_without_is_empty)] pub fn len(&self) -> usize { self.vec.len() } } pub type WidgetWrapper<'a> = DynBorrower<'a, dyn Widget>;