use image::DynamicImage; use crate::{ ActiveSensors, HashMap, Painter, SensorMap, TextureHandle, TextureUpdates, Textures, Widget, WidgetId, WidgetLike, render::Primitives, util::{Id, IdTracker}, }; use std::{ any::{Any, TypeId}, ops::{Index, IndexMut}, sync::mpsc::{Receiver, Sender, channel}, }; pub struct Ui { base: Option, widgets: Widgets, updates: Vec, del_recv: Receiver, del_send: Sender, primitives: Primitives, textures: Textures, full_redraw: bool, pub(super) active_sensors: ActiveSensors, pub(super) sensor_map: SensorMap, } #[derive(Default)] pub struct Widgets { ids: IdTracker, map: 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.id(); self.widgets.insert(id.id.duplicate(), w); id } 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.widgets.reserve(), TypeId::of::(), self.del_send.clone(), ) } pub fn add_texture(&mut self, image: DynamicImage) -> TextureHandle { self.textures.add(image) } 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_inner(base); } self.primitives = painter.finish(); } pub fn update(&mut self, ctx: &mut Ctx) -> UiRenderUpdates where Ctx: 'static, { while let Ok(id) = self.del_recv.try_recv() { self.widgets.delete(id); } if self.full_redraw { self.redraw_all(ctx); self.full_redraw = false; UiRenderUpdates { primitives: Some(&self.primitives), textures: self.textures.updates(), } } else if self.updates.is_empty() { UiRenderUpdates { primitives: None, textures: self.textures.updates(), } } else { // TODO: partial updates self.redraw_all(ctx); self.updates.drain(..); UiRenderUpdates { primitives: Some(&self.primitives), textures: self.textures.updates(), } } } pub fn needs_redraw(&self) -> bool { self.full_redraw || !self.updates.is_empty() } pub fn num_widgets(&self) -> usize { self.widgets.len() } } 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 { ids: IdTracker::default(), map: HashMap::new(), } } pub fn get_dyn(&self, id: &WidgetId) -> &dyn Widget { self.map.get(&id.id).unwrap().as_ref() } pub fn get>(&self, id: &WidgetId) -> Option<&W> { self.map.get(&id.id).unwrap().as_any().downcast_ref() } pub fn get_mut>(&mut self, id: &WidgetId) -> Option<&mut W> { self.map .get_mut(&id.id) .unwrap() .as_any_mut() .downcast_mut() } pub fn insert(&mut self, id: Id, widget: impl Widget) { self.map.insert(id, Box::new(widget)); } pub fn insert_any(&mut self, id: Id, widget: Box>) { self.map.insert(id, widget); } pub fn delete(&mut self, id: Id) { self.map.remove(&id); self.ids.free(id); } pub fn reserve(&mut self) -> Id { self.ids.next() } pub fn len(&self) -> usize { self.map.len() } pub fn is_empty(&self) -> bool { self.map.is_empty() } } 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 { let (del_send, del_recv) = channel(); Self { base: Default::default(), widgets: Widgets::new(), updates: Default::default(), primitives: Default::default(), textures: Textures::default(), full_redraw: false, active_sensors: Default::default(), sensor_map: Default::default(), del_send, del_recv, } } } pub struct UiRenderUpdates<'a> { pub primitives: Option<&'a Primitives>, pub textures: TextureUpdates<'a>, }