use std::sync::mpsc::{Receiver, Sender, channel}; use crate::{ Axis, IdLike, SizeRule, SizeRules, 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, } impl Widgets { pub fn new() -> Self { let (send, recv) = channel(); Self { needs_redraw: Default::default(), vec: Default::default(), waiting: 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()) } /// 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) -> 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 } /// useful for debugging pub fn set_label(&mut self, id: impl IdLike, label: String) { self.data_mut(id.id()).unwrap().label = label; } /// Whether this widget owns a movable retained region. pub fn is_region_node(&self, id: impl IdLike) -> bool { self.data(id).unwrap().region_node } /// Chooses whether this widget's retained drawing has one movable region /// of its own. Changing the boundary redraws the subtree once so every /// primitive names the right coordinate space. pub fn set_region_node(&mut self, id: impl IdLike, region_node: bool) { let id = id.id(); let data = self.data_mut(id).unwrap(); if data.region_node == region_node { return; } data.region_node = region_node; self.needs_redraw.insert(id); } /// The length rules whoever draws this widget applies to its box. pub fn size_rules(&self, id: impl IdLike) -> SizeRules { self.data(id).unwrap().size } /// Sets one axis's rule. The widget is marked rather than its parent /// because the parent is not known here; `redraw` escalates a changed /// declared length to whoever resolves it. pub fn set_size_rule(&mut self, id: impl IdLike, axis: Axis, rule: SizeRule) { let id = id.id(); let data = self.data_mut(id).unwrap(); if *data.size.axis_mut(axis) == rule { return; } *data.size.axis_mut(axis) = rule; self.needs_redraw.insert(id); } /// Both axes at once, for a caller holding a pair. pub fn set_size_rules( &mut self, id: impl IdLike, x: impl Into, y: impl Into, ) { let id = id.id(); self.set_size_rule(id, Axis::X, x.into()); self.set_size_rule(id, Axis::Y, y.into()); } 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); 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() } }