diff --git a/src/layout/painter.rs b/src/layout/painter.rs index a845bf8..9ad568a 100644 --- a/src/layout/painter.rs +++ b/src/layout/painter.rs @@ -7,6 +7,7 @@ use crate::{ util::{HashMap, HashSet, Id, TrackedArena}, }; +/// makes your surfaces look pretty pub struct Painter<'a, 'c> { ctx: &'a mut PainterCtx<'c>, region: UiRegion, @@ -22,6 +23,7 @@ pub struct Painter<'a, 'c> { id: Id, } +/// context for a painter; lets you draw and redraw widgets pub struct PainterCtx<'a> { pub widgets: &'a Widgets, pub active: &'a mut HashMap, @@ -36,12 +38,15 @@ pub struct PainterCtx<'a> { draw_started: HashSet, } +/// stores information for children about the highest level parent that needed their size +/// so that they can redraw the parent if their size changes #[derive(Clone, Copy, Debug, Default)] pub struct ResizeRef { x: Option<(Id, (UiVec2, Len))>, y: Option<(Id, (UiVec2, Len))>, } +/// important non rendering data for retained drawing #[derive(Debug)] pub struct WidgetInstance { pub id: Id, @@ -55,6 +60,7 @@ pub struct WidgetInstance { pub layer: usize, } +/// data to be stored in Ui to create PainterCtxs easily #[derive(Default)] pub struct PainterData { pub widgets: Widgets, @@ -85,6 +91,9 @@ impl<'a> PainterCtx<'a> { } } + /// redraws a widget that's currently active (drawn) + /// can be called on something already drawn or removed, + /// will just return if so pub fn redraw(&mut self, id: Id) { if self.draw_started.contains(&id) { return; @@ -94,12 +103,15 @@ impl<'a> PainterCtx<'a> { }; let mut resize = active.resize; + // set resize back after redrawing let finish = |s: &mut Self, resize| { if let Some(active) = s.active.get_mut(&id) { + // might need to get_or_insert here instead of just assuming active.resize = resize; } }; + // check if a parent depends on the desired size of this, if so then redraw it first // TODO: this is stupid having 2 of these, don't ask me what the consequences are if let Some((rid, (outer, old_desired))) = &mut resize.x { let new_desired = SizeCtx { @@ -194,6 +206,7 @@ impl<'a> PainterCtx<'a> { let mut old_children = old_children.unwrap_or_default(); let mut resize = ResizeRef::default(); if let Some(active) = self.active.get_mut(&id) { + // check to see if we can skip drawing first if active.parent != parent { panic!("Cannot draw the same widget twice (2)"); } @@ -205,11 +218,13 @@ impl<'a> PainterCtx<'a> { self.mov(id, from, region); return; } + // if not, then maintain resize and track old children to remove unneeded let active = self.remove(id).unwrap(); old_children = active.children; resize = active.resize; } + // draw widget self.draw_started.insert(id); let mut painter = Painter { @@ -225,7 +240,6 @@ impl<'a> PainterCtx<'a> { children_height: Default::default(), }; - // draw widgets painter.ctx.widgets.get_dyn_dynamic(id).draw(&mut painter); let children_width = painter.children_width; @@ -243,6 +257,7 @@ impl<'a> PainterCtx<'a> { mask: painter.mask, layer, }; + // set resize for children who's size this widget depends on for (cid, outer) in children_width { if let Some(w) = self.active.get_mut(&cid) && w.resize.x.is_none() @@ -257,12 +272,15 @@ impl<'a> PainterCtx<'a> { w.resize.y = Some((id, outer)) } } + + // remove old children that weren't kept for c in &old_children { if !instance.children.contains(c) { self.remove_rec(*c); } } + // update modules for m in self.modules.iter_mut() { m.on_draw(&instance); } @@ -467,16 +485,20 @@ impl SizeCtx<'_> { } fn width_inner(&mut self, id: Id) -> Len { + // first check cache if let Some(&(outer, len)) = self.cache_width.get(&id) && outer == self.outer { self.checked_width.insert(id, (self.outer, len)); return len; } + // store self vars that need to be maintained let self_outer = self.outer; let self_id = self.id; + // get size of input id self.id = id; let len = self.widgets.get_dyn_dynamic(id).desired_width(self); + // restore vars & update cache + checked self.outer = self_outer; self.id = self_id; self.cache_width.insert(id, (self.outer, len));