diff --git a/core/src/ui/draw_state.rs b/core/src/ui/draw_state.rs deleted file mode 100644 index ffd6bc1..0000000 --- a/core/src/ui/draw_state.rs +++ /dev/null @@ -1,196 +0,0 @@ -use crate::{ - ActiveData, Axis, EventsLike, Painter, SizeCtx, StrongWidget, UiRegion, UiRenderState, UiVec2, - WidgetId, Widgets, - render::MaskIdx, - util::{HashSet, forget_ref}, -}; - -/// state maintained between widgets during painting -pub struct Drawer<'a> { - pub(super) widgets: &'a mut Widgets, - pub(super) data: &'a mut PainterData, - pub(super) events: &'a mut dyn EventsLike, - pub(super) render: &'a mut UiRenderState, - root: Option<&'a StrongWidget>, - draw_started: HashSet, -} - -impl<'a> Drawer<'a> { - /// redraws a widget that's currently active (drawn) - pub fn redraw(&mut self, id: WidgetId) { - self.widgets.needs_redraw.remove(&id); - self.draw_started.remove(&id); - // check if parent depends on the desired size of this, if so then redraw it first - for axis in [Axis::X, Axis::Y] { - if let Some(&(outer, old)) = self.render.cache.size.axis_dyn(axis).get(&id) - && let Some(current) = self.render.active.get(&id) - && let Some(pid) = current.parent - { - self.render.cache.size.axis_dyn(axis).remove(&id); - let new = self.size_ctx(id, outer).len_axis(id, axis); - self.render - .cache - .size - .axis_dyn(axis) - .insert(id, (outer, new)); - if new != old { - self.redraw(pid); - } - } - } - - if self.draw_started.contains(&id) { - return; - } - - let Some(active) = self.remove(id, false) else { - return; - }; - - self.draw_inner( - active.layer, - id, - active.region, - active.parent, - active.mask, - Some(active.children), - ); - } - - pub(super) fn size_ctx<'b>(&'b mut self, source: WidgetId, outer: UiVec2) -> SizeCtx<'b> { - SizeCtx { - source, - cache: &mut self.render.cache, - text: &mut self.data.text, - textures: &mut self.data.textures, - widgets: &self.widgets, - outer, - output_size: self.render.output_size, - id: source, - } - } - - pub(super) fn draw_inner( - &mut self, - layer: usize, - id: WidgetId, - region: UiRegion, - parent: Option, - mask: MaskIdx, - old_children: Option>, - ) { - let mut old_children = old_children.unwrap_or_default(); - if let Some(active) = self.render.active.get_mut(&id) - && !self.widgets.needs_redraw.contains(&id) - { - // check to see if we can skip drawing first - if active.region == region { - return; - } else if active.region.size() == region.size() { - // TODO: epsilon? - let from = active.region; - self.mov(id, from, region); - return; - } - // if not, then maintain resize and track old children to remove unneeded - let active = self.remove(id, false).unwrap(); - old_children = active.children; - } - - // draw widget - self.draw_started.insert(id); - - let mut painter = Painter { - drawer: self, - region, - mask, - layer, - id, - textures: Vec::new(), - primitives: Vec::new(), - children: Vec::new(), - }; - - let mut widget = painter.drawer.widgets.get_dyn_dynamic(id); - widget.draw(&mut painter); - drop(widget); - - let Painter { - drawer: _, - region, - mask, - textures, - primitives, - children, - layer, - id, - } = painter; - - // add to active - let active = ActiveData { - id, - region, - parent, - textures, - primitives, - children, - mask, - layer, - }; - - // remove old children that weren't kept - for c in &old_children { - if !active.children.contains(c) { - self.remove_rec(*c); - } - } - - // update modules - self.events.draw(&active); - self.render.active.insert(id, active); - } - - fn mov(&mut self, id: WidgetId, from: UiRegion, to: UiRegion) { - let active = self.render.active.get_mut(&id).unwrap(); - for h in &active.primitives { - let region = self.render.layers[h.layer].region_mut(h); - *region = region.outside(&from).within(&to); - } - active.region = active.region.outside(&from).within(&to); - // SAFETY: children cannot be recursive - let children = unsafe { forget_ref(&active.children) }; - for child in children { - self.mov(*child, from, to); - } - } - - /// NOTE: instance textures are cleared and self.textures freed - fn remove(&mut self, id: WidgetId, undraw: bool) -> Option { - let mut active = self.render.active.remove(&id); - if let Some(active) = &mut active { - for h in &active.primitives { - let mask = self.render.layers.free(h); - if mask != MaskIdx::NONE { - self.data.masks.remove(mask); - } - } - active.textures.clear(); - self.data.textures.free(); - if undraw { - self.events.undraw(active); - } - } - active - } - - fn remove_rec(&mut self, id: WidgetId) -> Option { - self.render.cache.remove(id); - let inst = self.remove(id, true); - if let Some(inst) = &inst { - for c in &inst.children { - self.remove_rec(*c); - } - } - inst - } -} diff --git a/core/src/ui/mod.rs b/core/src/ui/mod.rs index ad07b6d..2998cbc 100644 --- a/core/src/ui/mod.rs +++ b/core/src/ui/mod.rs @@ -2,11 +2,9 @@ use crate::{Mask, TextData, Textures, WeakWidget, WidgetId, Widgets, util::Track mod active; mod cache; -// mod draw_state; mod painter; mod render_state; mod size; -mod state; pub use active::*; pub use painter::Painter; diff --git a/core/src/ui/state.rs b/core/src/ui/state.rs deleted file mode 100644 index f154552..0000000 --- a/core/src/ui/state.rs +++ /dev/null @@ -1,3 +0,0 @@ -// pub struct DynState { -// -// } diff --git a/examples/view.rs b/examples/view.rs index ead842f..b8e06cf 100644 --- a/examples/view.rs +++ b/examples/view.rs @@ -15,19 +15,22 @@ type Rsc = DefaultRsc; struct Test { #[root] root: WeakWidget, + cur: WeakState, } impl Test { pub fn new(rsc: &mut Rsc) -> Self { let root = rect(Color::RED).add(rsc); - Self { root } + let cur = rsc.create_state(root, false); + Self { root, cur } } pub fn toggle(&self, rsc: &mut Rsc) { - let rect = (self.root)(rsc); - if rect.color == Color::RED { - rect.color = Color::BLUE; + let cur = &mut rsc[self.cur]; + *cur = !*cur; + if *cur { + rsc[self.root].color = Color::BLUE; } else { - rect.color = Color::RED; + rsc[self.root].color = Color::RED; } } } diff --git a/src/default/mod.rs b/src/default/mod.rs index dd3e253..2c2f08f 100644 --- a/src/default/mod.rs +++ b/src/default/mod.rs @@ -17,6 +17,7 @@ mod event; mod input; mod render; mod sense; +mod state; mod task; pub use app::*; @@ -25,6 +26,7 @@ pub use event::*; pub use input::*; pub use render::*; pub use sense::*; +pub use state::*; pub use task::*; pub type Proxy = EventLoopProxy; @@ -98,6 +100,7 @@ pub struct DefaultRsc { pub ui: UiData, pub events: EventManager, pub tasks: Tasks, + pub state: WidgetState, _state: PhantomData, } @@ -109,11 +112,16 @@ impl DefaultRsc { ui: Default::default(), events: Default::default(), tasks, + state: Default::default(), _state: Default::default(), }, recv, ) } + + pub fn create_state(&mut self, id: impl IdLike, data: T) -> WeakState { + self.state.add(id.id(), data) + } } impl UiRsc for DefaultRsc { @@ -158,6 +166,16 @@ impl HasTasks for DefaultRsc { } } +impl HasWidgetState for DefaultRsc { + fn widget_state(&self) -> &WidgetState { + &self.state + } + + fn widget_state_mut(&mut self) -> &mut WidgetState { + &mut self.state + } +} + pub struct DefaultApp { rsc: DefaultRsc, render: UiRenderState, @@ -289,3 +307,47 @@ impl AppState for DefaultApp { self.state.exit(&mut self.rsc, &mut self.render); } } + +pub trait RscIdx { + type Output; + fn get(self, rsc: &Rsc) -> &Self::Output; + fn get_mut(self, rsc: &mut Rsc) -> &mut Self::Output; +} + +impl>> std::ops::Index for DefaultRsc { + type Output = I::Output; + + fn index(&self, index: I) -> &Self::Output { + index.get(self) + } +} + +impl>> std::ops::IndexMut for DefaultRsc { + fn index_mut(&mut self, index: I) -> &mut Self::Output { + index.get_mut(self) + } +} + +impl RscIdx for WeakWidget { + type Output = W; + + fn get(self, rsc: &Rsc) -> &Self::Output { + &rsc.ui().widgets[self] + } + + fn get_mut(self, rsc: &mut Rsc) -> &mut Self::Output { + &mut rsc.ui_mut().widgets[self] + } +} + +impl RscIdx for WeakState { + type Output = T; + + fn get(self, rsc: &Rsc) -> &Self::Output { + rsc.widget_state().get(self) + } + + fn get_mut(self, rsc: &mut Rsc) -> &mut Self::Output { + rsc.widget_state_mut().get_mut(self) + } +} diff --git a/src/default/state.rs b/src/default/state.rs new file mode 100644 index 0000000..395a1cf --- /dev/null +++ b/src/default/state.rs @@ -0,0 +1,67 @@ +use iris_core::{WidgetId, util::HashMap}; +use std::{ + any::{Any, TypeId}, + marker::PhantomData, +}; + +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +struct Key { + id: WidgetId, + ty: TypeId, + i: usize, +} + +#[derive(Default)] +pub struct WidgetState { + counts: HashMap<(WidgetId, TypeId), usize>, + map: HashMap>, +} + +impl WidgetState { + pub fn new() -> Self { + Self::default() + } + pub fn add(&mut self, id: WidgetId, data: T) -> WeakState { + let ty = TypeId::of::(); + let count = self.counts.entry((id, ty)).or_default(); + let key = Key { ty, i: *count, id }; + self.map.insert(key, Box::new(data)); + *count += 1; + WeakState { + key, + _pd: PhantomData, + } + } + pub fn remove(&mut self, state: WeakState) { + self.map.remove(&state.key); + } + pub fn get(&self, state: WeakState) -> &T { + self.map.get(&state.key).unwrap().downcast_ref().unwrap() + } + pub fn get_mut(&mut self, state: WeakState) -> &mut T { + self.map + .get_mut(&state.key) + .unwrap() + .downcast_mut() + .unwrap() + } +} + +#[derive(Clone, Copy)] +pub struct WeakState { + key: Key, + _pd: PhantomData, +} + +pub trait HasWidgetState { + fn widget_state(&self) -> &WidgetState; + fn widget_state_mut(&mut self) -> &mut WidgetState; +} + +impl<'a, T: 'static> FnOnce<(&'a mut WidgetState,)> for WeakState { + type Output = &'a mut T; + + extern "rust-call" fn call_once(self, (state,): (&'a mut WidgetState,)) -> Self::Output { + state.get_mut(self) + } +}