use crate::{ ActiveSensors, HashMap, Painter, SenseCtx, Sensor, SensorMap, Widget, WidgetId, WidgetLike, primitive::Primitives, util::{IDTracker, Id}, }; use std::{ any::{Any, TypeId}, ops::{Index, IndexMut}, }; pub struct Ui { ids: IDTracker, base: Option, widgets: Widgets, updates: Vec, active_sensors: ActiveSensors, sensor_map: SensorMap, primitives: Primitives, full_redraw: bool, } #[derive(Default)] pub struct Widgets(HashMap>>); impl Ui { pub fn add, Tag>( &mut self, w: impl WidgetLike, ) -> WidgetId { w.add(self) } pub fn add_widget>(&mut self, w: W) -> WidgetId { self.push(w) } pub fn push>(&mut self, w: W) -> WidgetId { let id = self.ids.next(); self.widgets.insert(id.duplicate(), w); WidgetId::new(id, TypeId::of::()) } pub fn set>(&mut self, i: &WidgetId, w: W) { self.widgets.insert(i.id.duplicate(), w); } pub fn set_base(&mut self, w: impl WidgetLike) { self.base = Some(w.add(self).erase_type()); self.full_redraw = true; } pub fn new() -> Self where Ctx: 'static, { Self::default() } pub fn get>(&self, id: &WidgetId) -> Option<&W> { self.widgets.get(id) } pub fn get_mut>(&mut self, id: &WidgetId) -> Option<&mut W> { self.widgets.get_mut(id) } pub fn id>(&mut self) -> WidgetId { WidgetId::new(self.ids.next(), TypeId::of::()) } pub fn redraw_all(&mut self, ctx: &mut Ctx) where Ctx: 'static, { self.active_sensors.clear(); let mut painter = Painter::new( &self.widgets, ctx, &mut self.sensor_map, &mut self.active_sensors, ); if let Some(base) = &self.base { painter.draw(base); } self.primitives = painter.finish(); } pub fn add_sensor(&mut self, id: &WidgetId, f: Sensor) { self.sensor_map .entry(id.id.duplicate()) .or_default() .push(f); } pub fn run_sensors(&mut self, ctx: &mut Ctx) where Ctx: SenseCtx + 'static, { for sensors in self.active_sensors.clone().iter().rev() { for sensor in sensors { if ctx.active(&sensor.trigger) { (sensor.f.box_clone())(self, ctx); } } } } pub fn update(&mut self, ctx: &mut Ctx) -> Option<&Primitives> where Ctx: 'static, { if self.full_redraw { self.redraw_all(ctx); self.full_redraw = false; return Some(&self.primitives); } if self.updates.is_empty() { return None; } self.redraw_all(ctx); self.updates.drain(..); Some(&self.primitives) } pub fn needs_redraw(&self) -> bool { self.full_redraw || !self.updates.is_empty() } } impl, Ctx> Index<&WidgetId> for Ui { type Output = W; fn index(&self, id: &WidgetId) -> &Self::Output { self.get(id).unwrap() } } impl, Ctx> IndexMut<&WidgetId> for Ui { fn index_mut(&mut self, id: &WidgetId) -> &mut Self::Output { self.updates.push(id.clone().erase_type()); self.get_mut(id).unwrap() } } impl Widgets { pub fn new() -> Self { Self(HashMap::new()) } pub fn get_dyn(&self, id: &WidgetId) -> &dyn Widget { self.0.get(&id.id).unwrap().as_ref() } pub fn get>(&self, id: &WidgetId) -> Option<&W> { self.0.get(&id.id).unwrap().as_any().downcast_ref() } pub fn get_mut>(&mut self, id: &WidgetId) -> Option<&mut W> { self.0.get_mut(&id.id).unwrap().as_any_mut().downcast_mut() } pub fn insert(&mut self, id: Id, widget: impl Widget) { self.0.insert(id, Box::new(widget)); } pub fn insert_any(&mut self, id: Id, widget: Box>) { self.0.insert(id, widget); } } impl dyn Widget { pub fn as_any(&self) -> &dyn Any { self } pub fn as_any_mut(&mut self) -> &mut dyn Any { self } } impl Default for Ui { fn default() -> Self { Self { ids: Default::default(), base: Default::default(), widgets: Widgets::new(), updates: Default::default(), primitives: Default::default(), full_redraw: false, active_sensors: Default::default(), sensor_map: Default::default(), } } }