use std::sync::mpsc::{Receiver, Sender, channel}; use crate::{ IdLike, StrongWidget, WeakWidget, Widget, WidgetData, WidgetId, util::{DynBorrower, HashSet, SlotVec, forget_mut, to_mut}, }; pub struct Widgets { pub needs_redraw: HashSet, vec: SlotVec, send: Sender, recv: Receiver, pub(crate) waiting: HashSet, named: HashSet, } impl Widgets { pub fn new() -> Self { let (send, recv) = channel(); Self { needs_redraw: Default::default(), vec: Default::default(), waiting: Default::default(), named: Default::default(), send, recv, } } 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()) } 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) -> StrongWidget { let id = self.vec.add(WidgetData::new(widget)); StrongWidget::new(id, self.send.clone()) } pub fn add_weak(&mut self, widget: W) -> WeakWidget { let id = self.vec.add(WidgetData::new(widget)); self.waiting.insert(id); WeakWidget::new(id) } #[track_caller] pub fn upgrade(&mut self, rf: WeakWidget) -> StrongWidget { 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" ) } StrongWidget::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 set_label(&mut self, id: impl IdLike, label: String) { let id = id.id(); self.data_mut(id).unwrap().label = label; self.named.insert(id); } pub fn named(&self) -> impl Iterator + '_ { self.named.iter().copied() } pub fn data_mut(&mut self, id: impl IdLike) -> Option<&mut WidgetData> { self.vec.get_mut(id.id()) } pub fn free_next(&mut self) -> Option { let next = self.recv.try_recv().ok()?; self.vec.free(next); self.named.remove(&next); Some(next) } #[allow(clippy::len_without_is_empty)] pub fn len(&self) -> usize { self.vec.len() } } impl Default for Widgets { fn default() -> Self { Self::new() } } pub type WidgetWrapper<'a> = DynBorrower<'a, dyn Widget>; impl std::ops::Index for Widgets where I::Widget: Sized + Widget, { type Output = I::Widget; fn index(&self, id: I) -> &Self::Output { self.get(&id).unwrap() } } impl std::ops::IndexMut for Widgets where I::Widget: Sized + Widget, { fn index_mut(&mut self, id: I) -> &mut Self::Output { self.get_mut(&id).unwrap() } }