use crate::{ Mask, MoveOffset, Paints, TextData, Textures, WeakWidget, WidgetId, Widgets, util::TrackedArena, }; use std::{ cell::{Ref, RefCell, RefMut}, ops::{Deref, DerefMut}, rc::Rc, }; mod access; mod active; mod painter; mod render_state; pub use access::*; pub use active::*; pub use painter::{DrawResult, Painter}; pub use render_state::*; #[derive(Default)] pub struct UiData { pub widgets: Widgets, pub paints: Paints, pub textures: Textures, pub text: TextData, pub masks: TrackedArena, pub move_offsets: TrackedArena, animating: Vec, } #[derive(Clone)] pub struct RenderHandle { pub(crate) render_state: Rc>, } impl RenderHandle { /// The retained result of the last completed frame. The framework holds /// the corresponding mutable borrow for the whole of a render update, so /// a read attempted while that state is incomplete fails at the boundary /// instead of observing half a frame. pub fn get(&self) -> Ref<'_, UiRenderState> { self.render_state .try_borrow() .expect("render state cannot be read while a frame is being rendered") } pub(crate) fn get_mut(&self) -> RefMut<'_, UiRenderState> { self.render_state .try_borrow_mut() .expect("render state cannot be mutated while it is being read") } } impl Default for RenderHandle { fn default() -> Self { Self { render_state: Rc::new(RefCell::new(UiRenderState::new())), } } } #[derive(Default)] pub struct Ui { data: UiData, pub(crate) render_state: RenderHandle, } impl Ui { /// A read-only handle to the retained result of the last completed frame. /// The handle is owned so a caller may keep its read guard while mutating /// unrelated resources on the `Rsc` that owns this `Ui`. pub fn render_state(&self) -> RenderHandle { self.render_state.clone() } pub fn resize(&self, size: impl Into) { self.render_state.get_mut().resize(size); } pub fn set_density(&mut self, density: f32) { self.data.text.density = density; self.render_state.get_mut().set_density(density); } } impl Deref for Ui { type Target = UiData; fn deref(&self) -> &Self::Target { &self.data } } impl DerefMut for Ui { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.data } } impl UiData { /// Ask for `id`'s [`crate::Widget::tick`] to run every frame until it /// says it is done. Idempotent -- registering an already-animating /// widget is the ordinary case (a second fling before the first /// settled) and must not tick it twice per frame. pub fn animate(&mut self, id: WidgetId) { if !self.animating.contains(&id) { self.animating.push(id); } } pub fn tick_animations(&mut self, now: std::time::Instant) -> bool { let mut registered = std::mem::take(&mut self.animating); registered.retain(|&id| match self.widgets.get_dyn_mut(id) { Some(widget) => widget.tick(now), None => false, }); for id in registered { self.animate(id); } !self.animating.is_empty() } } pub trait UiRsc { fn ui(&self) -> &Ui; fn ui_mut(&mut self) -> &mut Ui; fn draw<'a>(&mut self, root: impl Into>) where Self: Sized, { let render_state = self.ui().render_state.clone(); render_state.get_mut().update(root, self); } #[allow(unused_variables)] fn on_add(&mut self, id: WeakWidget) {} #[allow(unused_variables)] fn on_remove(&mut self, id: WidgetId) {} #[allow(unused_variables)] fn on_draw(&mut self, active: &ActiveData) {} #[allow(unused_variables)] fn on_undraw(&mut self, active: &ActiveData) {} fn widgets(&self) -> &Widgets { &self.ui().widgets } fn widgets_mut(&mut self) -> &mut Widgets { &mut self.ui_mut().widgets } fn free(&mut self) { while let Some(id) = self.widgets_mut().free_next() { self.on_remove(id); } self.ui_mut().textures.free(); self.ui_mut().paints.free_released(); } }