use std::sync::mpsc::Sender; use crate::{ IdLike, Widget, WidgetData, WidgetHandle, WidgetId, WidgetRef, util::{DynBorrower, HashSet, SlotVec, forget_mut, to_mut}, }; pub struct Widgets { pub needs_redraw: HashSet, vec: SlotVec, send: Sender, pub(crate) waiting: HashSet, } impl Widgets { pub fn new(send: Sender) -> Self { Self { needs_redraw: Default::default(), vec: Default::default(), waiting: Default::default(), send, } } pub fn has_updates(&self) -> bool { !self.needs_redraw.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.needs_redraw.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(crate) fn get_dyn_dynamic<'a>(&self, id: WidgetId) -> WidgetWrapper<'a> { // SAFETY: must guarantee no other mutable references to this widget exist // done through the borrow variable let data = unsafe { forget_mut(to_mut(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 + Widget, { 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 + Widget, { self.get_dyn_mut(id.id())?.as_any_mut().downcast_mut() } pub fn add_strong(&mut self, widget: W) -> WidgetHandle { let id = self.vec.add(WidgetData::new(widget)); WidgetHandle::new(id, self.send.clone()) } pub fn add_weak(&mut self, widget: W) -> WidgetRef { let id = self.vec.add(WidgetData::new(widget)); self.waiting.insert(id); WidgetRef::new(id) } #[track_caller] pub fn upgrade(&mut self, rf: WidgetRef) -> WidgetHandle { if !self.waiting.remove(&rf.id()) { let label = self.label(rf); let id = rf.id(); panic!("widget '{label}' ({id:?}) was already added\ncannot add a widget twice; consider creating two") } WidgetHandle::new(rf.id(), self.send.clone()) } pub fn data(&self, id: impl IdLike) -> Option<&WidgetData> { self.vec.get(id.id()) } pub fn label(&self, id: impl IdLike) -> &String { &self.data(id.id()).unwrap().label } pub fn data_mut(&mut self, id: impl IdLike) -> Option<&mut WidgetData> { self.vec.get_mut(id.id()) } pub fn delete(&mut self, id: impl IdLike) { self.vec.free(id.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>;