diff --git a/core/src/attr.rs b/core/src/attr.rs index 8151669..d90b6c3 100644 --- a/core/src/attr.rs +++ b/core/src/attr.rs @@ -1,22 +1,22 @@ -use crate::{Ui, WidgetIdFn, WidgetLike, WidgetRef}; +use crate::{HasUi, WidgetIdFn, WidgetLike, WidgetRef}; pub trait WidgetAttr { type Input; - fn run(ui: &mut Ui, id: WidgetRef, input: Self::Input); + fn run(state: &mut State, id: WidgetRef, input: Self::Input); } pub trait Attrable { fn attr>(self, input: A::Input) -> impl WidgetIdFn; } -impl, Tag> Attrable for WL { +impl, Tag> Attrable for WL { fn attr>( self, input: A::Input, ) -> impl WidgetIdFn { - |ui| { - let id = self.add(ui); - A::run(ui, id.weak(), input); + |state| { + let id = self.add(state); + A::run(state, id.weak(), input); id } } diff --git a/core/src/event/ctx.rs b/core/src/event/ctx.rs index d002714..afc689e 100644 --- a/core/src/event/ctx.rs +++ b/core/src/event/ctx.rs @@ -8,13 +8,13 @@ pub struct EventCtx<'a, State, Data> { } pub struct EventIdCtx<'a, State, Data, W: ?Sized> { - pub widget: WidgetRef, + pub widget: WidgetRef, pub state: &'a mut State, pub data: &'a mut Data, } impl Deref for EventIdCtx<'_, State, Data, W> { - type Target = Ui; + type Target = Ui; fn deref(&self) -> &Self::Target { self.state.ui_ref() @@ -27,7 +27,7 @@ impl DerefMut for EventIdCtx<'_, State, Data, W> } } -impl<'a, State: HasUi + 'static, Data, W: Widget> EventIdCtx<'a, State, Data, W> { +impl<'a, State: HasUi + 'static, Data, W: Widget> EventIdCtx<'a, State, Data, W> { pub fn widget(&mut self) -> &mut W { &mut self.state.ui()[self.widget] } diff --git a/core/src/event/manager.rs b/core/src/event/manager.rs index 65fc378..01bc629 100644 --- a/core/src/event/manager.rs +++ b/core/src/event/manager.rs @@ -1,5 +1,6 @@ use crate::{ - ActiveData, Event, EventCtx, EventFn, EventLike, HasUi, IdLike, LayerId, WidgetData, WidgetId, + ActiveData, Event, EventCtx, EventFn, EventLike, HasRsc, HasUi, IdLike, LayerId, WidgetData, + WidgetId, util::{HashMap, TypeMap}, }; use std::{any::TypeId, rc::Rc}; @@ -21,7 +22,7 @@ impl EventManager { self.types.type_or_default() } - pub fn register, E: EventLike>( + pub fn register( &mut self, id: I, event: E, @@ -33,20 +34,28 @@ impl EventManager { pub fn type_key() -> TypeId { TypeId::of::>() } +} - pub fn remove(&mut self, id: WidgetId) { +pub trait EventsLike { + fn remove(&mut self, id: WidgetId); + fn draw(&mut self, data: &WidgetData, active: &ActiveData); + fn undraw(&mut self, data: &WidgetData, active: &ActiveData); +} + +impl EventsLike for EventManager { + fn remove(&mut self, id: WidgetId) { for m in self.types.values_mut() { m.remove(id); } } - pub fn draw(&mut self, data: &WidgetData, active: &ActiveData) { + fn draw(&mut self, data: &WidgetData, active: &ActiveData) { for t in &data.event_mgrs { self.types.get_mut(t).unwrap().draw(active); } } - pub fn undraw(&mut self, data: &WidgetData, active: &ActiveData) { + fn undraw(&mut self, data: &WidgetData, active: &ActiveData) { for t in &data.event_mgrs { self.types.get_mut(t).unwrap().undraw(active); } @@ -99,7 +108,7 @@ impl Default for TypeEventManager { impl TypeEventManager { fn register( &mut self, - id: impl IdLike, + id: impl IdLike, event: impl EventLike, f: impl for<'a> EventFn>, ) { @@ -112,7 +121,7 @@ impl TypeEventManager { pub fn run_fn<'a>( &mut self, - id: impl IdLike, + id: impl IdLike, ) -> impl for<'b> FnOnce(EventCtx>) + 'a { let fs = self.map.get(&id.id()).cloned().unwrap_or_default(); move |ctx| { @@ -128,21 +137,26 @@ impl TypeEventManager { } } -pub trait HasEvents: Sized + HasUi { - fn run_event( - &mut self, - id: impl IdLike, - data: &mut ::Data<'_>, - ); -} +pub trait HasEvents: Sized { + type State: HasRsc; -impl HasEvents for State { - fn run_event( + fn events(&mut self) -> &mut EventManager; + + fn register_event( &mut self, - id: impl IdLike, - data: &mut ::Data<'_>, - ) { - let f = self.ui().events.get_type::().run_fn(id); - f(EventCtx { state: self, data }) + id: I, + event: E, + f: impl for<'a> EventFn::Data<'a>>, + ) where + Self: HasUi, + { + let id = id.id(); + self.events().register(id, event, f); + self.ui() + .widgets + .data_mut(id) + .unwrap() + .event_mgrs + .insert(EventManager::::type_key::()); } } diff --git a/core/src/event/mod.rs b/core/src/event/mod.rs index 4edcdb6..3c82473 100644 --- a/core/src/event/mod.rs +++ b/core/src/event/mod.rs @@ -1,8 +1,10 @@ mod ctx; mod manager; +mod rsc; pub use ctx::*; pub use manager::*; +pub use rsc::*; pub trait Event: Sized + 'static + Clone { type Data<'a> = (); diff --git a/core/src/event/rsc.rs b/core/src/event/rsc.rs new file mode 100644 index 0000000..773349c --- /dev/null +++ b/core/src/event/rsc.rs @@ -0,0 +1,29 @@ +use crate::{Event, EventCtx, EventLike, EventManager, HasEvents, HasUi, IdLike}; + +pub trait HasRsc: Sized + 'static { + type Rsc: HasEvents + HasUi; + fn rsc(&self) -> &Self::Rsc; + fn rsc_mut(&mut self) -> &mut Self::Rsc; + + fn run_event(&mut self, id: impl IdLike, data: &mut ::Data<'_>) + where + Self: 'static, + { + let f = self.rsc_mut().events().get_type::().run_fn(id); + f(EventCtx { state: self, data }) + } + + fn events(&mut self) -> &mut EventManager { + self.rsc_mut().events() + } +} + +impl HasUi for R { + fn ui_ref(&self) -> &crate::Ui { + self.rsc().ui_ref() + } + + fn ui(&mut self) -> &mut crate::Ui { + self.rsc_mut().ui() + } +} diff --git a/core/src/lib.rs b/core/src/lib.rs index 62992b9..145c54a 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -18,7 +18,6 @@ mod num; mod orientation; mod primitive; mod render; -mod typed; mod ui; mod widget; diff --git a/core/src/render/mod.rs b/core/src/render/mod.rs index c91ca7b..323b585 100644 --- a/core/src/render/mod.rs +++ b/core/src/render/mod.rs @@ -59,7 +59,7 @@ impl UiRenderNode { } } - pub fn update(&mut self, device: &Device, queue: &Queue, ui: &mut Ui) { + pub fn update(&mut self, device: &Device, queue: &Queue, ui: &mut Ui) { self.active.clear(); for (i, primitives) in ui.layers.iter_mut() { self.active.push(i); diff --git a/core/src/typed.rs b/core/src/typed.rs deleted file mode 100644 index 9ad08d9..0000000 --- a/core/src/typed.rs +++ /dev/null @@ -1,9 +0,0 @@ -#[macro_export] -macro_rules! core_state { - ($vis: vis $state: ty) => { - $vis type WidgetHandle> = $crate::WidgetHandle<$state, W>; - $vis type WidgetHandles> = $crate::WidgetHandles<$state, W>; - $vis type WidgetRef> = $crate::WidgetRef<$state, W>; - $vis type Ui = $crate::Ui<$state>; - }; -} diff --git a/core/src/ui/draw_state.rs b/core/src/ui/draw_state.rs index cc25647..4bd29f2 100644 --- a/core/src/ui/draw_state.rs +++ b/core/src/ui/draw_state.rs @@ -1,20 +1,22 @@ use crate::{ - ActiveData, Axis, Painter, SizeCtx, Ui, UiRegion, UiVec2, WidgetId, + ActiveData, Axis, EventsLike, Painter, SizeCtx, Ui, UiRegion, UiVec2, WidgetId, render::MaskIdx, util::{HashSet, forget_ref}, }; use std::ops::{Deref, DerefMut}; /// state maintained between widgets during painting -pub struct DrawState<'a, State> { - pub(super) ui: &'a mut Ui, +pub struct DrawState<'a> { + pub(super) ui: &'a mut Ui, + pub(super) events: &'a mut dyn EventsLike, draw_started: HashSet, } -impl<'a, State: 'static> DrawState<'a, State> { - pub fn new(ui: &'a mut Ui) -> Self { +impl<'a> DrawState<'a> { + pub fn new(ui: &'a mut Ui, events: &'a mut dyn EventsLike) -> Self { Self { ui, + events, draw_started: Default::default(), } } @@ -23,12 +25,10 @@ impl<'a, State: 'static> DrawState<'a, State> { while let Some(&id) = self.widgets.needs_redraw.iter().next() { self.redraw(id); } - self.free(); + self.ui.free(self.events); } /// 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: WidgetId) { self.widgets.needs_redraw.remove(&id); self.draw_started.remove(&id); @@ -65,11 +65,7 @@ impl<'a, State: 'static> DrawState<'a, State> { ); } - pub(super) fn size_ctx<'b>( - &'b mut self, - source: WidgetId, - outer: UiVec2, - ) -> SizeCtx<'b, State> { + pub(super) fn size_ctx<'b>(&'b mut self, source: WidgetId, outer: UiVec2) -> SizeCtx<'b> { SizeCtx { source, cache: &mut self.ui.cache, @@ -86,10 +82,10 @@ impl<'a, State: 'static> DrawState<'a, State> { // free all resources & cache for (id, active) in self.ui.active.drain() { let data = self.ui.widgets.data(id).unwrap(); - self.ui.events.undraw(data, &active); + self.events.undraw(data, &active); } self.ui.cache.clear(); - self.free(); + self.ui.free(self.events); self.layers.clear(); self.widgets.needs_redraw.clear(); @@ -107,26 +103,11 @@ impl<'a, State: 'static> DrawState<'a, State> { mask: MaskIdx, old_children: Option>, ) { - // I have no idea if these checks work lol - // the idea is u can't redraw stuff u already drew, - // and if parent is different then there's another copy with a different parent - // but this has a very weird issue where you can't move widgets unless u remove first - // so swapping is impossible rn I think? - // there's definitely better solutions like a counter (>1 = panic) but don't care rn - // if self.draw_started.contains(&id) { - // panic!( - // "Cannot draw the same widget ({}) twice (1)", - // self.widgets.data(&id).unwrap().label - // ); - // } let mut old_children = old_children.unwrap_or_default(); if let Some(active) = self.ui.active.get_mut(&id) && !self.ui.widgets.needs_redraw.contains(&id) { // check to see if we can skip drawing first - if active.parent != parent { - panic!("Cannot draw the same widget twice (2)"); - } if active.region == region { return; } else if active.region.size() == region.size() { @@ -190,7 +171,7 @@ impl<'a, State: 'static> DrawState<'a, State> { // update modules let data = self.ui.widgets.data(id).unwrap(); - self.ui.events.draw(data, &active); + self.events.draw(data, &active); self.active.insert(id, active); } @@ -222,7 +203,7 @@ impl<'a, State: 'static> DrawState<'a, State> { self.textures.free(); if undraw { let data = self.ui.widgets.data(id).unwrap(); - self.ui.events.undraw(data, active); + self.events.undraw(data, active); } } active @@ -240,14 +221,14 @@ impl<'a, State: 'static> DrawState<'a, State> { } } -impl Deref for DrawState<'_, State> { - type Target = Ui; +impl Deref for DrawState<'_> { + type Target = Ui; fn deref(&self) -> &Self::Target { self.ui } } -impl DerefMut for DrawState<'_, State> { +impl DerefMut for DrawState<'_> { fn deref_mut(&mut self) -> &mut Self::Target { self.ui } diff --git a/core/src/ui/mod.rs b/core/src/ui/mod.rs index 6371b3a..055ead7 100644 --- a/core/src/ui/mod.rs +++ b/core/src/ui/mod.rs @@ -1,6 +1,6 @@ use crate::{ - Event, EventFn, EventLike, EventManager, IdLike, Mask, PixelRegion, PrimitiveLayers, TextData, - TextureHandle, Textures, Widget, WidgetHandle, WidgetId, WidgetLike, Widgets, + EventsLike, IdLike, Mask, PixelRegion, PrimitiveLayers, TextData, TextureHandle, Textures, + Widget, WidgetHandle, WidgetId, Widgets, ui::draw_state::DrawState, util::{HashMap, TrackedArena, Vec2}, }; @@ -22,10 +22,9 @@ use cache::*; pub use painter::Painter; pub use size::*; -pub struct Ui { +pub struct Ui { // TODO: edit visibilities - pub widgets: Widgets, - pub events: EventManager, + pub widgets: Widgets, // retained painter state pub active: HashMap, @@ -36,56 +35,44 @@ pub struct Ui { pub masks: TrackedArena, pub cache: Cache, - root: Option>, + pub root: Option, + old_root: Option, recv: Receiver, send: Sender, - full_redraw: bool, resized: bool, } -pub trait HasUi: Sized { - fn ui_ref(&self) -> &Ui; - fn ui(&mut self) -> &mut Ui; +pub trait HasUi: Sized + 'static { + fn ui_ref(&self) -> &Ui; + fn ui(&mut self) -> &mut Ui; } -impl Ui { - pub fn add, Tag>( - &mut self, - w: impl WidgetLike, - ) -> WidgetHandle { - w.add(self) - } - +impl Ui { /// useful for debugging - pub fn set_label(&mut self, id: impl IdLike, label: String) { + pub fn set_label(&mut self, id: impl IdLike, label: String) { self.widgets.data_mut(id.id()).unwrap().label = label; } - pub fn label(&self, id: impl IdLike) -> &String { + pub fn label(&self, id: impl IdLike) -> &String { &self.widgets.data(id.id()).unwrap().label } - pub fn add_widget>(&mut self, w: W) -> WidgetHandle { + pub fn add_widget(&mut self, w: W) -> WidgetHandle { WidgetHandle::new(self.widgets.add(w), self.send.clone()) } - pub fn set_root(&mut self, w: impl WidgetLike) { - self.root = Some(w.add(self)); - self.full_redraw = true; - } - pub fn new() -> Self { Self::default() } - pub fn get>(&self, id: &I) -> Option<&I::Widget> + pub fn get(&self, id: &I) -> Option<&I::Widget> where I::Widget: Sized, { self.widgets.get(id) } - pub fn get_mut>(&mut self, id: &I) -> Option<&mut I::Widget> + pub fn get_mut(&mut self, id: &I) -> Option<&mut I::Widget> where I::Widget: Sized, { @@ -96,49 +83,39 @@ impl Ui { self.textures.add(image) } - pub fn register_event( - &mut self, - id: impl IdLike, - event: E, - f: impl for<'a> EventFn::Data<'a>>, - ) { - self.events.register(id.id(), event, f); - self.widgets - .data_mut(id) - .unwrap() - .event_mgrs - .insert(EventManager::::type_key::()); - } - pub fn resize(&mut self, size: impl Into) { self.output_size = size.into(); self.resized = true; } - pub fn update(&mut self) { - if self.full_redraw { - DrawState::new(self).redraw_all(); - self.full_redraw = false; + pub fn update(&mut self, events: &mut dyn EventsLike) { + if self.root_changed() { + DrawState::new(self, events).redraw_all(); + self.old_root = self.root.as_ref().map(|r| r.id()); } else if self.widgets.has_updates() { - DrawState::new(self).redraw_updates(); + DrawState::new(self, events).redraw_updates(); } if self.resized { self.resized = false; - DrawState::new(self).redraw_all(); + DrawState::new(self, events).redraw_all(); } } /// free any resources that don't have references anymore - fn free(&mut self) { + fn free(&mut self, events: &mut dyn EventsLike) { for id in self.recv.try_iter() { - self.events.remove(id); + events.remove(id); self.widgets.delete(id); } self.textures.free(); } + pub fn root_changed(&self) -> bool { + self.root.as_ref().map(|r| r.id()) != self.old_root + } + pub fn needs_redraw(&self) -> bool { - self.full_redraw || self.widgets.has_updates() + self.root_changed() || self.widgets.has_updates() } pub fn num_widgets(&self) -> usize { @@ -161,7 +138,7 @@ impl Ui { } } - pub fn window_region(&self, id: &impl IdLike) -> Option { + pub fn window_region(&self, id: &impl IdLike) -> Option { let region = self.active.get(&id.id())?.region; Some(region.to_px(self.output_size)) } @@ -174,7 +151,7 @@ impl Ui { } } -impl> Index for Ui +impl Index for Ui where I::Widget: Sized, { @@ -185,7 +162,7 @@ where } } -impl> IndexMut for Ui +impl IndexMut for Ui where I::Widget: Sized, { @@ -194,12 +171,11 @@ where } } -impl Default for Ui { +impl Default for Ui { fn default() -> Self { let (send, recv) = channel(); Self { widgets: Default::default(), - events: Default::default(), active: Default::default(), layers: Default::default(), masks: Default::default(), @@ -207,8 +183,8 @@ impl Default for Ui { textures: Default::default(), cache: Default::default(), output_size: Vec2::ZERO, - root: Default::default(), - full_redraw: false, + root: None, + old_root: None, send, recv, resized: false, diff --git a/core/src/ui/painter.rs b/core/src/ui/painter.rs index 730ff2c..dc707b2 100644 --- a/core/src/ui/painter.rs +++ b/core/src/ui/painter.rs @@ -7,8 +7,8 @@ use crate::{ }; /// makes your surfaces look pretty -pub struct Painter<'a, 'b, State> { - pub(super) state: &'a mut DrawState<'b, State>, +pub struct Painter<'a, 'b> { + pub(super) state: &'a mut DrawState<'b>, pub(super) region: UiRegion, pub(super) mask: MaskIdx, @@ -19,7 +19,7 @@ pub struct Painter<'a, 'b, State> { pub(super) id: WidgetId, } -impl<'a, 'c, State: 'static> Painter<'a, 'c, State> { +impl<'a, 'c> Painter<'a, 'c> { fn primitive_at(&mut self, primitive: P, region: UiRegion) { let h = self.state.layers.write( self.layer, @@ -52,17 +52,17 @@ impl<'a, 'c, State: 'static> Painter<'a, 'c, State> { } /// Draws a widget within this widget's region. - pub fn widget(&mut self, id: &WidgetHandle) { + pub fn widget(&mut self, id: &WidgetHandle) { self.widget_at(id, self.region); } /// Draws a widget somewhere within this one. /// Useful for drawing child widgets in select areas. - pub fn widget_within(&mut self, id: &WidgetHandle, region: UiRegion) { + pub fn widget_within(&mut self, id: &WidgetHandle, region: UiRegion) { self.widget_at(id, region.within(&self.region)); } - fn widget_at(&mut self, id: &WidgetHandle, region: UiRegion) { + fn widget_at(&mut self, id: &WidgetHandle, region: UiRegion) { self.children.push(id.id()); self.state .draw_inner(self.layer, id.id(), region, Some(self.id), self.mask, None); @@ -95,15 +95,11 @@ impl<'a, 'c, State: 'static> Painter<'a, 'c, State> { self.region } - pub fn size>(&mut self, id: &WidgetHandle) -> Size { + pub fn size(&mut self, id: &WidgetHandle) -> Size { self.size_ctx().size(id) } - pub fn len_axis>( - &mut self, - id: &WidgetHandle, - axis: Axis, - ) -> Len { + pub fn len_axis(&mut self, id: &WidgetHandle, axis: Axis) -> Len { match axis { Axis::X => self.size_ctx().width(id), Axis::Y => self.size_ctx().height(id), @@ -138,7 +134,7 @@ impl<'a, 'c, State: 'static> Painter<'a, 'c, State> { &self.id } - pub fn size_ctx(&mut self) -> SizeCtx<'_, State> { + pub fn size_ctx(&mut self) -> SizeCtx<'_> { self.state.size_ctx(self.id, self.region.size()) } } diff --git a/core/src/ui/size.rs b/core/src/ui/size.rs index eecc1f9..6f82492 100644 --- a/core/src/ui/size.rs +++ b/core/src/ui/size.rs @@ -3,11 +3,11 @@ use crate::{ UiVec2, WidgetAxisFns, WidgetId, Widgets, XAxis, YAxis, ui::cache::Cache, util::Vec2, }; -pub struct SizeCtx<'a, State> { +pub struct SizeCtx<'a> { pub text: &'a mut TextData, pub textures: &'a mut Textures, pub(super) source: WidgetId, - pub(super) widgets: &'a Widgets, + pub(super) widgets: &'a Widgets, pub(super) cache: &'a mut Cache, /// TODO: should this be pub? rn used for sized pub outer: UiVec2, @@ -15,7 +15,7 @@ pub struct SizeCtx<'a, State> { pub(super) id: WidgetId, } -impl SizeCtx<'_, State> { +impl SizeCtx<'_> { pub fn id(&self) -> &WidgetId { &self.id } @@ -45,22 +45,22 @@ impl SizeCtx<'_, State> { len } - pub fn width(&mut self, id: impl IdLike) -> Len { + pub fn width(&mut self, id: impl IdLike) -> Len { self.len_inner::(id.id()) } - pub fn height(&mut self, id: impl IdLike) -> Len { + pub fn height(&mut self, id: impl IdLike) -> Len { self.len_inner::(id.id()) } - pub fn len_axis(&mut self, id: impl IdLike, axis: Axis) -> Len { + pub fn len_axis(&mut self, id: impl IdLike, axis: Axis) -> Len { match axis { Axis::X => self.width(id), Axis::Y => self.height(id), } } - pub fn size(&mut self, id: impl IdLike) -> Size { + pub fn size(&mut self, id: impl IdLike) -> Size { let id = id.id(); Size { x: self.width(id), diff --git a/core/src/widget/data.rs b/core/src/widget/data.rs index b6481a7..68ef4f3 100644 --- a/core/src/widget/data.rs +++ b/core/src/widget/data.rs @@ -2,16 +2,16 @@ use std::any::TypeId; use crate::{Widget, util::HashSet}; -pub struct WidgetData { - pub widget: Box>, +pub struct WidgetData { + pub widget: Box, pub label: String, pub event_mgrs: HashSet, /// dynamic borrow checking pub borrowed: bool, } -impl WidgetData { - pub fn new>(widget: W) -> Self { +impl WidgetData { + pub fn new(widget: W) -> Self { let mut label = std::any::type_name::().to_string(); if let (Some(first), Some(last)) = (label.find(":"), label.rfind(":")) { label = label.split_at(first).0.to_string() + "::" + label.split_at(last + 1).1; diff --git a/core/src/widget/handle.rs b/core/src/widget/handle.rs index 521c818..001a67e 100644 --- a/core/src/widget/handle.rs +++ b/core/src/widget/handle.rs @@ -1,12 +1,7 @@ -use std::{ - marker::{PhantomData, Unsize}, - mem::MaybeUninit, - ops::CoerceUnsized, - sync::mpsc::Sender, -}; +use std::{marker::Unsize, mem::MaybeUninit, ops::CoerceUnsized, sync::mpsc::Sender}; use crate::{ - Ui, Widget, + Widget, util::{RefCounter, SlotId}, }; @@ -17,42 +12,39 @@ pub type WidgetId = SlotId; /// a signal is sent to the owning UI to clean up the resources. /// /// TODO: ergonomic clones when they get put in rust-analyzer & don't cause ICEs? -pub struct WidgetHandle> { +pub struct WidgetHandle { pub(super) id: WidgetId, counter: RefCounter, send: Sender, ty: *const W, - state: PhantomData, } /// A weak handle to a widget. /// Will not keep it alive, but can still be used for indexing like WidgetHandle. -pub struct WidgetRef> { +pub struct WidgetRef { pub(super) id: WidgetId, #[allow(unused)] ty: *const W, - state: PhantomData, } -pub struct WidgetHandles> { - pub h: WidgetHandle, - pub r: WidgetRef, +pub struct WidgetHandles { + pub h: WidgetHandle, + pub r: WidgetRef, } -impl + ?Sized + Unsize>> WidgetHandle { - pub fn any(self) -> WidgetHandle> { +impl> WidgetHandle { + pub fn any(self) -> WidgetHandle { self } } -impl WidgetHandle { +impl WidgetHandle { pub(crate) fn new(id: WidgetId, send: Sender) -> Self { Self { id, counter: RefCounter::new(), send, ty: unsafe { MaybeUninit::zeroed().assume_init() }, - state: PhantomData, } } @@ -64,28 +56,24 @@ impl WidgetHandle { self.counter.refs() } - pub fn weak(&self) -> WidgetRef { + pub fn weak(&self) -> WidgetRef { let Self { ty, id, .. } = *self; - WidgetRef { - ty, - id, - state: PhantomData, - } + WidgetRef { ty, id } } - pub fn handles(self) -> WidgetHandles { + pub fn handles(self) -> WidgetHandles { let r = self.weak(); WidgetHandles { h: self, r } } } -impl WidgetRef { +impl WidgetRef { pub fn id(&self) -> WidgetId { self.id } } -impl Drop for WidgetHandle { +impl Drop for WidgetHandle { fn drop(&mut self) { if self.counter.drop() { let _ = self.send.send(self.id); @@ -93,64 +81,52 @@ impl Drop for WidgetHandle { } } -pub trait WidgetIdFn>: - FnOnce(&mut Ui) -> WidgetHandle -{ -} -impl) -> WidgetHandle> WidgetIdFn - for F -{ -} +pub trait WidgetIdFn: FnOnce(&mut State) -> WidgetHandle {} +impl WidgetHandle> WidgetIdFn for F {} -pub trait IdLike { - type Widget: Widget + ?Sized + 'static; +pub trait IdLike { + type Widget: Widget + ?Sized + 'static; fn id(&self) -> WidgetId; } -impl + ?Sized> IdLike for &WidgetHandle { +impl IdLike for &WidgetHandle { type Widget = W; fn id(&self) -> WidgetId { self.id } } -impl + ?Sized> IdLike for WidgetHandle { +impl IdLike for WidgetHandle { type Widget = W; fn id(&self) -> WidgetId { self.id } } -impl + ?Sized> IdLike for WidgetRef { +impl IdLike for WidgetRef { type Widget = W; fn id(&self) -> WidgetId { self.id } } -impl IdLike for WidgetId { - type Widget = dyn Widget; +impl IdLike for WidgetId { + type Widget = dyn Widget; fn id(&self) -> WidgetId { *self } } -impl, U: ?Sized, State> CoerceUnsized> - for WidgetHandle -{ -} -impl, U: ?Sized> CoerceUnsized> - for WidgetRef -{ -} +impl, U: ?Sized> CoerceUnsized> for WidgetHandle {} +impl, U: ?Sized> CoerceUnsized> for WidgetRef {} -impl Clone for WidgetRef { +impl Clone for WidgetRef { fn clone(&self) -> Self { *self } } -impl Copy for WidgetRef {} -impl PartialEq for WidgetRef { +impl Copy for WidgetRef {} +impl PartialEq for WidgetRef { fn eq(&self, other: &Self) -> bool { self.id == other.id } diff --git a/core/src/widget/like.rs b/core/src/widget/like.rs index 6b41226..c32ffb7 100644 --- a/core/src/widget/like.rs +++ b/core/src/widget/like.rs @@ -1,36 +1,38 @@ +use crate::HasUi; + use super::*; use std::marker::Unsize; -pub trait WidgetLike: Sized { - type Widget: Widget + ?Sized + Unsize> + 'static; +pub trait WidgetLike: Sized { + type Widget: Widget + ?Sized + Unsize + 'static; - fn add(self, ui: &mut Ui) -> WidgetHandle; + fn add(self, state: &mut State) -> WidgetHandle; fn with_id( self, - f: impl FnOnce(&mut Ui, WidgetHandle) -> WidgetHandle, + f: impl FnOnce(&mut State, WidgetHandle) -> WidgetHandle, ) -> impl WidgetIdFn { - move |ui| { - let id = self.add(ui); - f(ui, id) + move |state| { + let id = self.add(state); + f(state, id) } } - fn set_root(self, ui: &mut Ui) { - ui.set_root(self); + fn set_root(self, state: &mut State) { + state.ui().root = Some(self.add(state)); } - fn handles(self, ui: &mut Ui) -> WidgetHandles { - self.add(ui).handles() + fn handles(self, state: &mut State) -> WidgetHandles { + self.add(state).handles() } } pub trait WidgetArrLike { - fn ui(self, ui: &mut Ui) -> WidgetArr; + fn add(self, state: &mut State) -> WidgetArr; } -impl WidgetArrLike for WidgetArr { - fn ui(self, _: &mut Ui) -> WidgetArr { +impl WidgetArrLike for WidgetArr { + fn add(self, _: &mut State) -> WidgetArr { self } } @@ -41,12 +43,12 @@ macro_rules! impl_widget_arr { impl_widget_arr!($n;$($W)*;$(${concat($W,Tag)})*); }; ($n:expr;$($W:ident)*;$($Tag:ident)*) => { - impl,$Tag,)*> WidgetArrLike for ($($W,)*) { - fn ui(self, ui: &mut Ui) -> WidgetArr { + impl,$Tag,)*> WidgetArrLike for ($($W,)*) { + fn add(self, state: &mut State) -> WidgetArr<$n> { #[allow(non_snake_case)] let ($($W,)*) = self; WidgetArr::new( - [$($W.add(ui),)*], + [$($W.add(state),)*], ) } } diff --git a/core/src/widget/mod.rs b/core/src/widget/mod.rs index 917a2c2..89348ad 100644 --- a/core/src/widget/mod.rs +++ b/core/src/widget/mod.rs @@ -1,4 +1,4 @@ -use crate::{Axis, AxisT, Len, Painter, SizeCtx, Ui}; +use crate::{Axis, AxisT, Len, Painter, SizeCtx}; use std::any::Any; mod data; @@ -13,18 +13,18 @@ pub use like::*; pub use tag::*; pub use widgets::*; -pub trait Widget: Any { - fn draw(&mut self, painter: &mut Painter); - fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len; - fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len; +pub trait Widget: Any { + fn draw(&mut self, painter: &mut Painter); + fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len; + fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len; } -pub trait WidgetAxisFns { - fn desired_len(&mut self, ctx: &mut SizeCtx) -> Len; +pub trait WidgetAxisFns { + fn desired_len(&mut self, ctx: &mut SizeCtx) -> Len; } -impl + ?Sized> WidgetAxisFns for W { - fn desired_len(&mut self, ctx: &mut SizeCtx) -> Len { +impl WidgetAxisFns for W { + fn desired_len(&mut self, ctx: &mut SizeCtx) -> Len { match A::get() { Axis::X => self.desired_width(ctx), Axis::Y => self.desired_height(ctx), @@ -32,17 +32,17 @@ impl + ?Sized> WidgetAxisFns for W { } } -impl Widget for () { - fn draw(&mut self, _: &mut Painter) {} - fn desired_width(&mut self, _: &mut SizeCtx) -> Len { +impl Widget for () { + fn draw(&mut self, _: &mut Painter) {} + fn desired_width(&mut self, _: &mut SizeCtx) -> Len { Len::ZERO } - fn desired_height(&mut self, _: &mut SizeCtx) -> Len { + fn desired_height(&mut self, _: &mut SizeCtx) -> Len { Len::ZERO } } -impl dyn Widget { +impl dyn Widget { pub fn as_any(&self) -> &dyn Any { self } @@ -55,31 +55,31 @@ impl dyn Widget { /// A function that returns a widget given a UI. /// Useful for defining trait functions on widgets that create a parent widget so that the children /// don't need to be IDs yet -pub trait WidgetFn + ?Sized>: FnOnce(&mut Ui) -> W {} -impl + ?Sized, F: FnOnce(&mut Ui) -> W> WidgetFn for F {} +pub trait WidgetFn: FnOnce(&mut State) -> W {} +impl W> WidgetFn for F {} -pub struct WidgetArr { - pub arr: [WidgetHandle; LEN], +pub struct WidgetArr { + pub arr: [WidgetHandle; LEN], } -impl WidgetArr { - pub fn new(arr: [WidgetHandle; LEN]) -> Self { +impl WidgetArr { + pub fn new(arr: [WidgetHandle; LEN]) -> Self { Self { arr } } } pub trait WidgetOption { - fn get(self, ui: &mut Ui) -> Option>; + fn get(self, state: &mut State) -> Option; } impl WidgetOption for () { - fn get(self, _: &mut Ui) -> Option> { + fn get(self, _: &mut State) -> Option { None } } -impl) -> Option>> WidgetOption for F { - fn get(self, ui: &mut Ui) -> Option> { - self(ui) +impl Option> WidgetOption for F { + fn get(self, state: &mut State) -> Option { + self(state) } } diff --git a/core/src/widget/tag.rs b/core/src/widget/tag.rs index e3121e0..aba11fa 100644 --- a/core/src/widget/tag.rs +++ b/core/src/widget/tag.rs @@ -1,46 +1,46 @@ use std::marker::Unsize; +use crate::HasUi; + use super::*; pub struct ArrTag; pub struct WidgetTag; -impl> WidgetLike for W { +impl WidgetLike for W { type Widget = W; - fn add(self, ui: &mut Ui) -> WidgetHandle { - ui.add_widget(self) + fn add(self, state: &mut State) -> WidgetHandle { + state.ui().add_widget(self) } } pub struct FnTag; -impl, F: FnOnce(&mut Ui) -> W> WidgetLike - for F -{ +impl W> WidgetLike for F { type Widget = W; - fn add(self, ui: &mut Ui) -> WidgetHandle { - self(ui).add(ui) + fn add(self, state: &mut State) -> WidgetHandle { + self(state).add(state) } } pub struct IdTag; -impl + Unsize> + 'static> - WidgetLike for WidgetHandle +impl + 'static> WidgetLike + for WidgetHandle { type Widget = W; - fn add(self, _: &mut Ui) -> WidgetHandle { + fn add(self, _: &mut State) -> WidgetHandle { self } } pub struct IdFnTag; impl< - State: 'static, - W: ?Sized + Widget + Unsize> + 'static, - F: FnOnce(&mut Ui) -> WidgetHandle, + State: HasUi, + W: ?Sized + Widget + Unsize + 'static, + F: FnOnce(&mut State) -> WidgetHandle, > WidgetLike for F { type Widget = W; - fn add(self, ui: &mut Ui) -> WidgetHandle { - self(ui) + fn add(self, state: &mut State) -> WidgetHandle { + self(state) } } diff --git a/core/src/widget/widgets.rs b/core/src/widget/widgets.rs index df84afe..5aa92c4 100644 --- a/core/src/widget/widgets.rs +++ b/core/src/widget/widgets.rs @@ -3,12 +3,12 @@ use crate::{ util::{DynBorrower, HashSet, SlotVec, forget_mut, to_mut}, }; -pub struct Widgets { +pub struct Widgets { pub needs_redraw: HashSet, - vec: SlotVec>, + vec: SlotVec, } -impl Default for Widgets { +impl Default for Widgets { fn default() -> Self { Self { needs_redraw: Default::default(), @@ -17,23 +17,23 @@ impl Default for Widgets { } } -impl Widgets { +impl Widgets { pub fn has_updates(&self) -> bool { !self.needs_redraw.is_empty() } - pub fn get_dyn(&self, id: WidgetId) -> Option<&dyn Widget> { + pub fn get_dyn(&self, id: WidgetId) -> Option<&dyn Widget> { Some(self.vec.get(id)?.widget.as_ref()) } - pub fn get_dyn_mut(&mut self, id: WidgetId) -> Option<&mut dyn Widget> { + pub fn get_dyn_mut(&mut self, id: WidgetId) -> Option<&mut dyn Widget> { self.needs_redraw.insert(id); Some(self.vec.get_mut(id)?.widget.as_mut()) } /// get_dyn but dynamic borrow checking of widgets /// lets you do recursive (tree) operations, like the painter does - pub(crate) fn get_dyn_dynamic<'a>(&self, id: WidgetId) -> WidgetWrapper<'a, State> { + pub(crate) fn get_dyn_dynamic<'a>(&self, id: WidgetId) -> WidgetWrapper<'a> { // SAFETY: must guarantee no other mutable references to this widget exist // done through the borrow variable let data = unsafe { forget_mut(to_mut(self.vec.get(id).unwrap())) }; @@ -43,37 +43,37 @@ impl Widgets { WidgetWrapper::new(data.widget.as_mut(), &mut data.borrowed) } - pub fn get>(&self, id: &I) -> Option<&I::Widget> + pub fn get(&self, id: &I) -> Option<&I::Widget> where I::Widget: Sized, { self.get_dyn(id.id())?.as_any().downcast_ref() } - pub fn get_mut>(&mut self, id: &I) -> Option<&mut I::Widget> + pub fn get_mut(&mut self, id: &I) -> Option<&mut I::Widget> where I::Widget: Sized, { self.get_dyn_mut(id.id())?.as_any_mut().downcast_mut() } - pub fn add>(&mut self, widget: W) -> WidgetId { + pub fn add(&mut self, widget: W) -> WidgetId { self.vec.add(WidgetData::new(widget)) } - pub fn data(&self, id: impl IdLike) -> Option<&WidgetData> { + pub fn data(&self, id: impl IdLike) -> Option<&WidgetData> { self.vec.get(id.id()) } - pub fn label(&self, id: impl IdLike) -> &String { + pub fn label(&self, id: impl IdLike) -> &String { &self.data(id.id()).unwrap().label } - pub fn data_mut(&mut self, id: impl IdLike) -> Option<&mut WidgetData> { + pub fn data_mut(&mut self, id: impl IdLike) -> Option<&mut WidgetData> { self.vec.get_mut(id.id()) } - pub fn delete(&mut self, id: impl IdLike) { + pub fn delete(&mut self, id: impl IdLike) { self.vec.free(id.id()); // not sure if there's any point in this // self.updates.remove(&id); @@ -85,4 +85,4 @@ impl Widgets { } } -pub type WidgetWrapper<'a, State> = DynBorrower<'a, dyn Widget>; +pub type WidgetWrapper<'a> = DynBorrower<'a, dyn Widget>; diff --git a/macro/src/lib.rs b/macro/src/lib.rs index b3031b5..ee00759 100644 --- a/macro/src/lib.rs +++ b/macro/src/lib.rs @@ -2,12 +2,10 @@ extern crate proc_macro; use proc_macro::TokenStream; use quote::quote; use syn::{ - Attribute, Block, Error, GenericParam, Generics, Ident, ItemStruct, ItemTrait, Meta, Signature, - Token, Visibility, + Attribute, Block, Error, GenericParam, Generics, Ident, ItemTrait, Signature, Token, + Visibility, parse::{Parse, ParseStream, Result}, parse_macro_input, parse_quote, - punctuated::Punctuated, - spanned::Spanned, }; struct Input { @@ -96,111 +94,3 @@ pub fn widget_trait(input: TokenStream) -> TokenStream { } .into() } - -#[proc_macro_derive(GlobalState, attributes(has))] -pub fn derive_global_state(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as ItemStruct); - let name = input.ident; - let mut impls = TokenStream::new(); - for field in input.fields { - let Some(attr) = field.attrs.iter().find(|a| a.path().is_ident("has")) else { - continue; - }; - let error: TokenStream = Error::new( - attr.span(), - "invalid attribute format; usage: #[has(HasTrait, trait_fn)]", - ) - .into_compile_error() - .into(); - let Meta::List(list) = &attr.meta else { - return error; - }; - match list.parse_args_with(Punctuated::::parse_terminated) { - Ok(list) => { - if list.len() != 2 { - return error; - } - let traitt = &list[0]; - let fn_name = &list[1]; - let field_name = field.ident; - let ty = field.ty; - impls.extend::( - quote! { - impl #traitt for #name { - fn #fn_name(&mut self) -> &mut #ty { - &mut self.#field_name - } - } - } - .into(), - ); - } - Err(..) => { - return error; - } - } - } - impls -} - -#[proc_macro_derive(HasUi)] -pub fn derive_has_ui(input: TokenStream) -> TokenStream { - has_ui(&parse_macro_input!(input)) -} - -fn has_ui(input: &ItemStruct) -> TokenStream { - let name = &input.ident; - let Some(field) = input - .fields - .iter() - .find(|f| f.ty == parse_quote!(Ui) || f.ty == parse_quote!(Ui)) - else { - return Error::new(name.span(), "could not find a Ui field for HasUi") - .into_compile_error() - .into(); - }; - let field = &field.ident; - quote! { - impl HasUi for #name { - fn ui_ref(&self) -> &iris::iris_core::Ui { - &self.#field - } - - fn ui(&mut self) -> &mut iris::iris_core::Ui { - &mut self.#field - } - } - } - .into() -} - -#[proc_macro_derive(DefaultUiState)] -pub fn derive_default_ui_state(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as ItemStruct); - let mut output = has_ui(&input); - let name = input.ident; - let Some(field) = input - .fields - .iter() - .find(|f| f.ty == parse_quote!(UiState) || f.ty == parse_quote!(UiState)) - else { - return Error::new( - name.span(), - "could not find a UiState field for HasUiState", - ) - .into_compile_error() - .into(); - }; - let field = &field.ident; - output.extend::( - quote! { - impl HasUiState for #name { - fn ui_state(&mut self) -> &mut iris::default::UiState { - &mut self.#field - } - } - } - .into(), - ); - output -} diff --git a/src/bin/test/main.rs b/src/bin/test/main.rs index 6096c2c..47b8c23 100644 --- a/src/bin/test/main.rs +++ b/src/bin/test/main.rs @@ -2,225 +2,230 @@ use cosmic_text::Family; use std::{cell::RefCell, rc::Rc}; use winit::{event::WindowEvent, event_loop::ActiveEventLoop, window::WindowAttributes}; -iris::state_prelude!(Client); +iris::state_prelude!(DefaultUiRsc); fn main() { App::::run(); } -#[derive(DefaultUiState)] pub struct Client { - ui: Ui, - ui_state: UiState, + rsc: DefaultUiRsc, info: WidgetRef, } +impl HasRsc for Client { + type Rsc = DefaultUiRsc; + + fn rsc(&self) -> &Self::Rsc { + &self.rsc + } + + fn rsc_mut(&mut self) -> &mut Self::Rsc { + &mut self.rsc + } +} + impl DefaultAppState for Client { fn new(event_loop: &ActiveEventLoop, _proxy: Proxy) -> Self { - let mut ui = Ui::new(); let window = event_loop .create_window(WindowAttributes::default()) .unwrap(); + let mut rsc = DefaultUiRsc::new(window); let info; - { - let ui = &mut ui; - let rrect = rect(Color::WHITE).radius(20); - let pad_test = ( - rrect.color(Color::BLUE), + let rrect = rect(Color::WHITE).radius(20); + let pad_test = ( + rrect.color(Color::BLUE), + ( + rrect + .color(Color::RED) + .sized((100, 100)) + .center() + .width(rest(2)), ( - rrect - .color(Color::RED) - .sized((100, 100)) - .center() - .width(rest(2)), - ( - rrect.color(Color::ORANGE), - rrect.color(Color::LIME).pad(10.0), - ) - .span(Dir::RIGHT) - .width(rest(2)), - rrect.color(Color::YELLOW), + rrect.color(Color::ORANGE), + rrect.color(Color::LIME).pad(10.0), ) .span(Dir::RIGHT) - .pad(10) - .width(rest(3)), + .width(rest(2)), + rrect.color(Color::YELLOW), ) .span(Dir::RIGHT) - .handles(ui); + .pad(10) + .width(rest(3)), + ) + .span(Dir::RIGHT) + .handles(&mut rsc); - let span_test = ( - rrect.color(Color::GREEN).width(100), - rrect.color(Color::ORANGE), - rrect.color(Color::CYAN), - rrect.color(Color::BLUE).width(rel(0.5)), - rrect.color(Color::MAGENTA).width(100), - rrect.color(Color::RED).width(100), + let span_test = ( + rrect.color(Color::GREEN).width(100), + rrect.color(Color::ORANGE), + rrect.color(Color::CYAN), + rrect.color(Color::BLUE).width(rel(0.5)), + rrect.color(Color::MAGENTA).width(100), + rrect.color(Color::RED).width(100), + ) + .span(Dir::LEFT) + .add(&mut rsc); + + let span_add = Span::empty(Dir::RIGHT).handles(&mut rsc); + + let add_button = rect(Color::LIME) + .radius(30) + .on(CursorSense::click(), move |mut ctx| { + let child = image(include_bytes!("assets/sungals.png")) + .center() + .add(&mut ctx.state.rsc); + ctx[span_add.r].children.push(child); + }) + .sized((150, 150)) + .align(Align::BOT_RIGHT); + + let del_button = rect(Color::RED) + .radius(30) + .on(CursorSense::click(), move |mut ctx| { + ctx[span_add.r].children.pop(); + }) + .sized((150, 150)) + .align(Align::BOT_LEFT); + + let span_add_test = (span_add.h, add_button, del_button).stack().add(&mut rsc); + + let btext = |content| wtext(content).size(30); + + let text_test = ( + btext("this is a").align(Align::LEFT), + btext("teeeeeeeest").align(Align::RIGHT), + btext("okkk\nokkkkkk!").align(Align::LEFT), + btext("hmm"), + btext("a"), + ( + btext("'").family(Family::Monospace).align(Align::TOP), + btext("'").family(Family::Monospace), + btext(":gamer mode").family(Family::Monospace), + rect(Color::CYAN).sized((10, 10)).center(), + rect(Color::RED).sized((100, 100)).center(), + rect(Color::PURPLE).sized((50, 50)).align(Align::TOP), ) - .span(Dir::LEFT) - .add(ui); + .span(Dir::RIGHT) + .center(), + wtext("pretty cool right?").size(50), + ) + .span(Dir::DOWN) + .add(&mut rsc); - let span_add = Span::empty(Dir::RIGHT).handles(ui); - - let add_button = rect(Color::LIME) - .radius(30) - .on(CursorSense::click(), move |mut ctx| { - let child = ctx.add(image(include_bytes!("assets/sungals.png")).center()); - ctx[span_add.r].children.push(child); - }) - .sized((150, 150)) - .align(Align::BOT_RIGHT); - - let del_button = rect(Color::RED) - .radius(30) - .on(CursorSense::click(), move |mut ctx| { - ctx[span_add.r].children.pop(); - }) - .sized((150, 150)) - .align(Align::BOT_LEFT); - - let span_add_test = (span_add.h, add_button, del_button).stack().add(ui); - - let btext = |content| wtext(content).size(30); - - let text_test = ( - btext("this is a").align(Align::LEFT), - btext("teeeeeeeest").align(Align::RIGHT), - btext("okkk\nokkkkkk!").align(Align::LEFT), - btext("hmm"), - btext("a"), + let texts = Span::empty(Dir::DOWN).gap(10).handles(&mut rsc); + let msg_area = texts.h.scrollable().masked().background(rect(Color::SKY)); + let add_text = wtext("add") + .editable(EditMode::MultiLine) + .text_align(Align::LEFT) + .size(30) + .attr::(()) + .on(Submit, move |mut ctx| { + let content = ctx.widget.edit(ctx.state.ui()).take(); + let text = wtext(content) + .editable(EditMode::MultiLine) + .size(30) + .text_align(Align::LEFT) + .wrap(true) + .attr::(()); + let msg_box = text + .background(rect(Color::WHITE.darker(0.5))) + .add(&mut ctx.state.rsc); + ctx[texts.r].children.push(msg_box); + }) + .handles(&mut rsc); + let text_edit_scroll = ( + msg_area.height(rest(1)), + ( + Rect::new(Color::WHITE.darker(0.9)), ( - btext("'").family(Family::Monospace).align(Align::TOP), - btext("'").family(Family::Monospace), - btext(":gamer mode").family(Family::Monospace), - rect(Color::CYAN).sized((10, 10)).center(), - rect(Color::RED).sized((100, 100)).center(), - rect(Color::PURPLE).sized((50, 50)).align(Align::TOP), + add_text.h.width(rest(1)), + Rect::new(Color::GREEN) + .on(CursorSense::click(), move |ctx| { + ctx.state.run_event::(add_text.r, &mut ()); + }) + .sized((40, 40)), ) .span(Dir::RIGHT) - .center(), - wtext("pretty cool right?").size(50), + .pad(10), ) - .span(Dir::DOWN) - .add(ui); - - let texts = Span::empty(Dir::DOWN).gap(10).handles(ui); - let msg_area = texts.h.scrollable().masked().background(rect(Color::SKY)); - let add_text = wtext("add") - .editable(EditMode::MultiLine) - .text_align(Align::LEFT) - .size(30) - .attr::(()) - .on(Submit, move |mut ctx| { - let content = ctx.widget.edit(ctx.state.ui()).take(); - let text = wtext(content) - .editable(EditMode::MultiLine) - .size(30) - .text_align(Align::LEFT) - .wrap(true) - .attr::(()); - let msg_box = text - .background(rect(Color::WHITE.darker(0.5))) - .add(&mut ctx); - ctx[texts.r].children.push(msg_box); - }) - .handles(ui); - let text_edit_scroll = ( - msg_area.height(rest(1)), - ( - Rect::new(Color::WHITE.darker(0.9)), - ( - add_text.h.width(rest(1)), - Rect::new(Color::GREEN) - .on(CursorSense::click(), move |ctx| { - ctx.state.run_event::(add_text.r, &mut ()); - }) - .sized((40, 40)), - ) - .span(Dir::RIGHT) - .pad(10), - ) - .stack() - .size(StackSize::Child(1)) - .layer_offset(1) - .align(Align::BOT), - ) - .span(Dir::DOWN) - .add(ui); - - let main = WidgetPtr::new().handles(ui); - - let vals = Rc::new(RefCell::new((0, Vec::new()))); - let mut switch_button = |color, to: WidgetHandle, label| { - let vec = &mut vals.borrow_mut().1; - let i = vec.len(); - if vec.is_empty() { - vec.push(None); - ui[main.r].set(to); - } else { - vec.push(Some(to)); - } - let vals = vals.clone(); - let rect = rect(color) - .on(CursorSense::click(), move |mut ctx| { - let (prev, vec) = &mut *vals.borrow_mut(); - if let Some(h) = vec[i].take() { - vec[*prev] = ctx[main.r].replace(h); - *prev = i; - } - ctx.widget().color = color.darker(0.3); - }) - .on( - CursorSense::HoverStart | CursorSense::unclick(), - move |mut ctx| { - ctx.widget().color = color.brighter(0.2); - }, - ) - .on(CursorSense::HoverEnd, move |mut ctx| { - ctx.widget().color = color; - }); - (rect, wtext(label).size(30).text_align(Align::CENTER)).stack() - }; - - let tabs = ( - switch_button(Color::RED, pad_test.h, "pad"), - switch_button(Color::GREEN, span_test, "span"), - switch_button(Color::BLUE, span_add_test, "image span"), - switch_button(Color::MAGENTA, text_test, "text layout"), - switch_button( - Color::YELLOW.mul_rgb(0.5), - text_edit_scroll, - "text edit scroll", - ), - ) - .span(Dir::RIGHT); - - info = wtext("").handles(ui); - let info_sect = info.h.pad(10).align(Align::RIGHT); - - ((tabs.height(40), main.h.pad(10)).span(Dir::DOWN), info_sect) .stack() - .set_root(ui); - } + .size(StackSize::Child(1)) + .layer_offset(1) + .align(Align::BOT), + ) + .span(Dir::DOWN) + .add(&mut rsc); - Self { - ui, - ui_state: UiState::new(window), - info: info.r, - } + let main = WidgetPtr::new().handles(&mut rsc); + + let vals = Rc::new(RefCell::new((0, Vec::new()))); + let mut switch_button = |color, to: WidgetHandle, label| { + let vec = &mut vals.borrow_mut().1; + let i = vec.len(); + if vec.is_empty() { + vec.push(None); + rsc.ui[main.r].set(to); + } else { + vec.push(Some(to)); + } + let vals = vals.clone(); + let rect = rect(color) + .on(CursorSense::click(), move |mut ctx| { + let (prev, vec) = &mut *vals.borrow_mut(); + if let Some(h) = vec[i].take() { + vec[*prev] = ctx[main.r].replace(h); + *prev = i; + } + ctx.widget().color = color.darker(0.3); + }) + .on( + CursorSense::HoverStart | CursorSense::unclick(), + move |mut ctx| { + ctx.widget().color = color.brighter(0.2); + }, + ) + .on(CursorSense::HoverEnd, move |mut ctx| { + ctx.widget().color = color; + }); + (rect, wtext(label).size(30).text_align(Align::CENTER)).stack() + }; + + let tabs = ( + switch_button(Color::RED, pad_test.h, "pad"), + switch_button(Color::GREEN, span_test, "span"), + switch_button(Color::BLUE, span_add_test, "image span"), + switch_button(Color::MAGENTA, text_test, "text layout"), + switch_button( + Color::YELLOW.mul_rgb(0.5), + text_edit_scroll, + "text edit scroll", + ), + ) + .span(Dir::RIGHT); + + info = wtext("").handles(&mut rsc); + let info_sect = info.h.pad(10).align(Align::RIGHT); + + ((tabs.height(40), main.h.pad(10)).span(Dir::DOWN), info_sect) + .stack() + .set_root(&mut rsc); + + Self { rsc, info: info.r } } fn window_event(&mut self, _: WindowEvent) { let new = format!( "widgets: {}\nactive:{}\nviews: {}", - self.ui.num_widgets(), - self.ui.active_widgets(), - self.ui_state.renderer.ui.view_count() + self.ui().num_widgets(), + self.ui().active_widgets(), + self.ui_state().renderer.ui.view_count() ); - if new != *self.ui[self.info].content { - *self.ui[self.info].content = new; + if new != *self.rsc.ui[self.info].content { + *self.rsc.ui[self.info].content = new; } - if self.ui.needs_redraw() { - self.ui_state.window.request_redraw(); + if self.ui().needs_redraw() { + self.ui_state().window.request_redraw(); } } } diff --git a/src/default/attr.rs b/src/default/attr.rs index 2d6a271..666ca31 100644 --- a/src/default/attr.rs +++ b/src/default/attr.rs @@ -4,11 +4,11 @@ use winit::dpi::{LogicalPosition, LogicalSize}; pub struct Selector; -impl + 'static> WidgetAttr for Selector { - type Input = WidgetRef>; +impl WidgetAttr for Selector { + type Input = WidgetRef; - fn run(ui: &mut Ui, container: WidgetRef, id: Self::Input) { - ui.register_event(container, CursorSense::click_or_drag(), move |ctx| { + fn run(state: &mut State, container: WidgetRef, id: Self::Input) { + state.register_event(container, CursorSense::click_or_drag(), move |ctx| { let region = ctx.state.ui().window_region(&id).unwrap(); let id_pos = region.top_left; let container_pos = ctx.state.ui().window_region(&container).unwrap().top_left; @@ -21,11 +21,11 @@ impl + 'static> WidgetAttr for Sel pub struct Selectable; -impl WidgetAttr> for Selectable { +impl WidgetAttr for Selectable { type Input = (); - fn run(ui: &mut Ui, id: WidgetRef>, _: Self::Input) { - ui.register_event(id, CursorSense::click_or_drag(), move |ctx| { + fn run(state: &mut State, id: WidgetRef, _: Self::Input) { + state.register_event(id, CursorSense::click_or_drag(), move |ctx| { select( ctx.state, id, @@ -37,9 +37,9 @@ impl WidgetAttr> for Selectable { } } -fn select( - state: &mut State, - id: WidgetRef>, +fn select( + state: &mut impl HasUiState, + id: WidgetRef, pos: Vec2, size: Vec2, dragging: bool, diff --git a/src/default/input.rs b/src/default/input.rs index 53e8d45..4aa96b7 100644 --- a/src/default/input.rs +++ b/src/default/input.rs @@ -66,7 +66,7 @@ impl Input { } } -impl UiState { +impl UiState { pub fn window_size(&self) -> Vec2 { let size = self.renderer.window().inner_size(); (size.width, size.height).into() diff --git a/src/default/mod.rs b/src/default/mod.rs index ad1e3a8..09b881f 100644 --- a/src/default/mod.rs +++ b/src/default/mod.rs @@ -24,17 +24,57 @@ pub use sense::*; pub type Proxy = EventLoopProxy; -pub struct UiState { +pub struct DefaultUiRsc { + pub ui: Ui, + pub ui_state: UiState, + pub events: EventManager, +} + +impl DefaultUiRsc { + pub fn new(window: impl Into>) -> Self { + Self { + ui: Ui::new(), + ui_state: UiState::new(window), + events: EventManager::default(), + } + } +} + +impl HasUi for DefaultUiRsc { + fn ui_ref(&self) -> &Ui { + &self.ui + } + + fn ui(&mut self) -> &mut Ui { + &mut self.ui + } +} + +impl> HasEvents for DefaultUiRsc { + type State = State; + + fn events(&mut self) -> &mut EventManager { + &mut self.events + } +} + +impl HasUiState for DefaultUiRsc { + fn ui_state(&mut self) -> &mut UiState { + &mut self.ui_state + } +} + +pub struct UiState { pub renderer: UiRenderer, pub input: Input, - pub focus: Option>>, + pub focus: Option>, pub clipboard: Clipboard, pub window: Arc, pub ime: usize, pub last_click: Instant, } -impl UiState { +impl UiState { pub fn new(window: impl Into>) -> Self { let window = window.into(); Self { @@ -50,14 +90,23 @@ impl UiState { } pub trait HasUiState: Sized + 'static + HasUi { - fn ui_state(&mut self) -> &mut UiState; - fn ui_with_ui_state(&mut self) -> (&mut Ui, &mut UiState) { + fn ui_state(&mut self) -> &mut UiState; + fn ui_with_ui_state(&mut self) -> (&mut Ui, &mut UiState) { // as long as you're not doing anything actually unhinged this should always work safely (unsafe { forget_mut(self.ui()) }, self.ui_state()) } } -pub trait DefaultAppState: Sized + 'static + HasUi + HasUiState { +impl HasUiState for R +where + R::Rsc: HasUiState, +{ + fn ui_state(&mut self) -> &mut UiState { + self.rsc_mut().ui_state() + } +} + +pub trait DefaultAppState: Sized + 'static + HasRsc + HasUi + HasUiState { type Event: 'static = (); fn new(event_loop: &ActiveEventLoop, proxy: Proxy) -> Self; #[allow(unused_variables)] @@ -80,6 +129,7 @@ impl AppState for State { } fn window_event(&mut self, event: WindowEvent, event_loop: &ActiveEventLoop) { + let events = unsafe { forget_mut(self.events()) }; let ui_state = self.ui_state(); let input_changed = ui_state.input.event(&event); let cursor_state = ui_state.cursor_state().clone(); @@ -100,7 +150,7 @@ impl AppState for State { match &event { WindowEvent::CloseRequested => event_loop.exit(), WindowEvent::RedrawRequested => { - ui.update(); + ui.update(events); ui_state.renderer.update(ui); ui_state.renderer.draw(); } diff --git a/src/default/render.rs b/src/default/render.rs index c650431..2392ba9 100644 --- a/src/default/render.rs +++ b/src/default/render.rs @@ -18,7 +18,7 @@ pub struct UiRenderer { } impl UiRenderer { - pub fn update(&mut self, ui: &mut Ui) { + pub fn update(&mut self, ui: &mut Ui) { self.ui.update(&self.device, &self.queue, ui); } diff --git a/src/default/sense.rs b/src/default/sense.rs index 22d2a80..fc36c50 100644 --- a/src/default/sense.rs +++ b/src/default/sense.rs @@ -142,11 +142,10 @@ pub trait SensorUi { fn run_sensors(&mut self, cursor: &CursorState, window_size: Vec2); } -impl SensorUi for State { +impl SensorUi for State { fn run_sensors(&mut self, cursor: &CursorState, window_size: Vec2) { let layers = std::mem::take(&mut self.ui().layers); - let mut active = - std::mem::take(&mut self.ui().events.get_type::().active); + let mut active = std::mem::take(&mut self.events().get_type::().active); for layer in layers.indices().rev() { let mut sensed = false; for (id, sensor) in active.get_mut(&layer).into_iter().flatten() { @@ -175,7 +174,7 @@ impl SensorUi for State { break; } } - self.ui().events.get_type::().active = active; + self.events().get_type::().active = active; self.ui().layers = layers; } } diff --git a/src/event.rs b/src/event.rs index fe48f28..ef60a8a 100644 --- a/src/event.rs +++ b/src/event.rs @@ -3,15 +3,15 @@ use crate::prelude::*; pub mod eventable { use super::*; widget_trait! { - pub trait Eventable; + pub trait Eventable; fn on( self, event: E, - f: impl for<'a> WidgetEventFn::Data<'a>, WL::Widget>, + f: impl for<'a> WidgetEventFn::Data<'a>, WL::Widget>, ) -> impl WidgetIdFn { - move |ui| { - let id = self.handles(ui); - ui.register_event(id.r, event.into_event(), move |ctx| { + move |state| { + let id = self.handles(state); + state.register_event(id.r, event.into_event(), move |ctx| { f(EventIdCtx { widget: id.r, state: ctx.state, diff --git a/src/lib.rs b/src/lib.rs index fd0a774..ff2fd78 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,20 +9,17 @@ pub mod event; pub mod typed; pub mod widget; -pub use iris_core; -pub use iris_macro; +pub use iris_core as core; +pub use iris_macro as macros; #[macro_export] macro_rules! state_prelude { ($vis:vis $state:ty) => { iris::event_state!($vis $state); - iris::iris_core::core_state!($vis $state); - iris::default_state!($vis $state); - iris::widget_state!($vis $state); $vis use iris::{ default::*, - iris_core::{len_fns::*, util::Vec2, *}, - iris_macro::*, + core::{len_fns::*, util::Vec2, *}, + macros::*, widget::*, }; }; diff --git a/src/typed.rs b/src/typed.rs index 962165d..21039ca 100644 --- a/src/typed.rs +++ b/src/typed.rs @@ -1,35 +1,3 @@ -#[macro_export] -macro_rules! default_state { - ($vis:vis $state:ty) => { - $vis type UiState = $crate::default::UiState<$state>; - }; -} - -#[macro_export] -macro_rules! widget_state { - ($vis:vis $state:ty) => { - $crate::widget_state!( - $vis $state; - Aligned, - LayerOffset, - MaxSize, - Offset, - Scroll, - Sized, - Span, - Stack, - Text, - TextEdit, - Masked, - WidgetPtr, - ); - $vis type TextBuilder = ()> = $crate::widget::TextBuilder<$state, O, H>; - }; - ($vis:vis $state:ty; $($ty:ident,)*) => { - $($vis type $ty = $crate::widget::$ty<$state>;)* - } -} - #[macro_export] macro_rules! event_state { ($vis:vis $state:ty) => { @@ -37,24 +5,32 @@ macro_rules! event_state { use super::*; #[allow(unused_imports)] use $crate::prelude::*; - pub trait EventableCtx, Tag> { fn on( self, event: E, - f: impl for<'a> WidgetEventFn<$state, ::Data<'a>, WL::Widget>, + f: impl for<'a> WidgetEventFn< + <$state as HasEvents>::State, + ::Data<'a>, + WL::Widget + >, ) -> impl WidgetIdFn<$state, WL::Widget>; } impl, Tag> EventableCtx for WL { fn on( self, event: E, - f: impl for<'a> WidgetEventFn::Data<'a>, WL::Widget>, - ) -> impl WidgetIdFn { + f: impl for<'a> WidgetEventFn< + <$state as HasEvents>::State, + ::Data<'a>, + WL::Widget + >, + ) -> impl WidgetIdFn<$state, WL::Widget> { eventable::Eventable::on(self, event, f) } } } + $vis type EventManager = $crate::prelude::EventManager<$state>; $vis use local_event_trait::*; }; } diff --git a/src/widget/image.rs b/src/widget/image.rs index 1daa838..ebe8722 100644 --- a/src/widget/image.rs +++ b/src/widget/image.rs @@ -5,24 +5,24 @@ pub struct Image { handle: TextureHandle, } -impl Widget for Image { - fn draw(&mut self, painter: &mut Painter) { +impl Widget for Image { + fn draw(&mut self, painter: &mut Painter) { painter.texture(&self.handle); } - fn desired_width(&mut self, _: &mut SizeCtx) -> Len { + fn desired_width(&mut self, _: &mut SizeCtx) -> Len { Len::abs(self.handle.size().x) } - fn desired_height(&mut self, _: &mut SizeCtx) -> Len { + fn desired_height(&mut self, _: &mut SizeCtx) -> Len { Len::abs(self.handle.size().y) } } -pub fn image(image: impl LoadableImage) -> impl WidgetFn { +pub fn image(image: impl LoadableImage) -> impl WidgetFn { let image = image.get_image().expect("Failed to load image"); - move |ui| Image { - handle: ui.add_texture(image), + move |state| Image { + handle: state.ui().add_texture(image), } } diff --git a/src/widget/mask.rs b/src/widget/mask.rs index b8d9fcf..5b16337 100644 --- a/src/widget/mask.rs +++ b/src/widget/mask.rs @@ -1,20 +1,20 @@ use crate::prelude::*; -pub struct Masked { - pub inner: WidgetHandle, +pub struct Masked { + pub inner: WidgetHandle, } -impl Widget for Masked { - fn draw(&mut self, painter: &mut Painter) { +impl Widget for Masked { + fn draw(&mut self, painter: &mut Painter) { painter.set_mask(painter.region()); painter.widget(&self.inner); } - fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { + fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { ctx.width(&self.inner) } - fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { + fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { ctx.height(&self.inner) } } diff --git a/src/widget/position/align.rs b/src/widget/position/align.rs index c6d513a..c475b4b 100644 --- a/src/widget/position/align.rs +++ b/src/widget/position/align.rs @@ -1,12 +1,12 @@ use crate::prelude::*; -pub struct Aligned { - pub inner: WidgetHandle, +pub struct Aligned { + pub inner: WidgetHandle, pub align: Align, } -impl Widget for Aligned { - fn draw(&mut self, painter: &mut Painter) { +impl Widget for Aligned { + fn draw(&mut self, painter: &mut Painter) { let region = match self.align.tuple() { (Some(x), Some(y)) => painter .size(&self.inner) @@ -25,11 +25,11 @@ impl Widget for Aligned { painter.widget_within(&self.inner, region); } - fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { + fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { ctx.width(&self.inner) } - fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { + fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { ctx.height(&self.inner) } } diff --git a/src/widget/position/layer.rs b/src/widget/position/layer.rs index ee17010..ef55139 100644 --- a/src/widget/position/layer.rs +++ b/src/widget/position/layer.rs @@ -1,23 +1,23 @@ use crate::prelude::*; -pub struct LayerOffset { - pub inner: WidgetHandle, +pub struct LayerOffset { + pub inner: WidgetHandle, pub offset: usize, } -impl Widget for LayerOffset { - fn draw(&mut self, painter: &mut Painter) { +impl Widget for LayerOffset { + fn draw(&mut self, painter: &mut Painter) { for _ in 0..self.offset { painter.next_layer(); } painter.widget(&self.inner); } - fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { + fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { ctx.width(&self.inner) } - fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { + fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { ctx.height(&self.inner) } } diff --git a/src/widget/position/max_size.rs b/src/widget/position/max_size.rs index 85ccd45..83071d8 100644 --- a/src/widget/position/max_size.rs +++ b/src/widget/position/max_size.rs @@ -1,13 +1,13 @@ use crate::prelude::*; -pub struct MaxSize { - pub inner: WidgetHandle, +pub struct MaxSize { + pub inner: WidgetHandle, pub x: Option, pub y: Option, } -impl MaxSize { - fn apply_to_outer(&self, ctx: &mut SizeCtx) { +impl MaxSize { + fn apply_to_outer(&self, ctx: &mut SizeCtx) { if let Some(x) = self.x { ctx.outer.x.select_len(x.apply_rest()); } @@ -17,12 +17,12 @@ impl MaxSize { } } -impl Widget for MaxSize { - fn draw(&mut self, painter: &mut Painter) { +impl Widget for MaxSize { + fn draw(&mut self, painter: &mut Painter) { painter.widget(&self.inner); } - fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { + fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { self.apply_to_outer(ctx); let width = ctx.width(&self.inner); if let Some(x) = self.x { @@ -34,7 +34,7 @@ impl Widget for MaxSize { } } - fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { + fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { self.apply_to_outer(ctx); let height = ctx.height(&self.inner); if let Some(y) = self.y { diff --git a/src/widget/position/offset.rs b/src/widget/position/offset.rs index 4e389d5..e7a19d8 100644 --- a/src/widget/position/offset.rs +++ b/src/widget/position/offset.rs @@ -1,21 +1,21 @@ use crate::prelude::*; -pub struct Offset { - pub inner: WidgetHandle, +pub struct Offset { + pub inner: WidgetHandle, pub amt: UiVec2, } -impl Widget for Offset { - fn draw(&mut self, painter: &mut Painter) { +impl Widget for Offset { + fn draw(&mut self, painter: &mut Painter) { let region = UiRegion::FULL.offset(self.amt); painter.widget_within(&self.inner, region); } - fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { + fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { ctx.width(&self.inner) } - fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { + fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { ctx.height(&self.inner) } } diff --git a/src/widget/position/pad.rs b/src/widget/position/pad.rs index 5a55508..26554ee 100644 --- a/src/widget/position/pad.rs +++ b/src/widget/position/pad.rs @@ -1,16 +1,16 @@ use crate::prelude::*; -pub struct Pad { +pub struct Pad { pub padding: Padding, - pub inner: WidgetHandle, + pub inner: WidgetHandle, } -impl Widget for Pad { - fn draw(&mut self, painter: &mut Painter) { +impl Widget for Pad { + fn draw(&mut self, painter: &mut Painter) { painter.widget_within(&self.inner, self.padding.region()); } - fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { + fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { let width = self.padding.left + self.padding.right; let height = self.padding.top + self.padding.bottom; ctx.outer.x.abs -= width; @@ -20,7 +20,7 @@ impl Widget for Pad { size } - fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { + fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { let width = self.padding.left + self.padding.right; let height = self.padding.top + self.padding.bottom; ctx.outer.x.abs -= width; diff --git a/src/widget/position/scroll.rs b/src/widget/position/scroll.rs index 727132b..c414b11 100644 --- a/src/widget/position/scroll.rs +++ b/src/widget/position/scroll.rs @@ -1,7 +1,7 @@ use crate::prelude::*; -pub struct Scroll { - inner: WidgetHandle, +pub struct Scroll { + inner: WidgetHandle, axis: Axis, amt: f32, snap_end: bool, @@ -9,8 +9,8 @@ pub struct Scroll { content_len: f32, } -impl Widget for Scroll { - fn draw(&mut self, painter: &mut Painter) { +impl Widget for Scroll { + fn draw(&mut self, painter: &mut Painter) { let output_len = painter.output_size().axis(self.axis); let container_len = painter.region().axis(self.axis).len(); let content_len = painter @@ -31,17 +31,17 @@ impl Widget for Scroll { painter.widget_within(&self.inner, region); } - fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { + fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { ctx.width(&self.inner) } - fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { + fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { ctx.height(&self.inner) } } -impl Scroll { - pub fn new(inner: WidgetHandle, axis: Axis) -> Self { +impl Scroll { + pub fn new(inner: WidgetHandle, axis: Axis) -> Self { Self { inner, axis, diff --git a/src/widget/position/sized.rs b/src/widget/position/sized.rs index 8c0aad1..8aed65e 100644 --- a/src/widget/position/sized.rs +++ b/src/widget/position/sized.rs @@ -1,13 +1,13 @@ use crate::prelude::*; -pub struct Sized { - pub inner: WidgetHandle, +pub struct Sized { + pub inner: WidgetHandle, pub x: Option, pub y: Option, } -impl Sized { - fn apply_to_outer(&self, ctx: &mut SizeCtx) { +impl Sized { + fn apply_to_outer(&self, ctx: &mut SizeCtx) { if let Some(x) = self.x { ctx.outer.x.select_len(x.apply_rest()); } @@ -17,17 +17,17 @@ impl Sized { } } -impl Widget for Sized { - fn draw(&mut self, painter: &mut Painter) { +impl Widget for Sized { + fn draw(&mut self, painter: &mut Painter) { painter.widget(&self.inner); } - fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { + fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { self.apply_to_outer(ctx); self.x.unwrap_or_else(|| ctx.width(&self.inner)) } - fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { + fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { self.apply_to_outer(ctx); self.y.unwrap_or_else(|| ctx.height(&self.inner)) } diff --git a/src/widget/position/span.rs b/src/widget/position/span.rs index e68fbbf..09ec245 100644 --- a/src/widget/position/span.rs +++ b/src/widget/position/span.rs @@ -1,14 +1,14 @@ use crate::prelude::*; use std::marker::PhantomData; -pub struct Span { - pub children: Vec>, +pub struct Span { + pub children: Vec, pub dir: Dir, pub gap: f32, } -impl Widget for Span { - fn draw(&mut self, painter: &mut Painter) { +impl Widget for Span { + fn draw(&mut self, painter: &mut Painter) { let total = self.len_sum(&mut painter.size_ctx()); let mut start = UiScalar::rel_min(); for child in &self.children { @@ -33,14 +33,14 @@ impl Widget for Span { } } - fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { + fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { match self.dir.axis { Axis::X => self.desired_len(ctx), Axis::Y => self.desired_ortho(ctx), } } - fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { + fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { match self.dir.axis { Axis::X => self.desired_ortho(ctx), Axis::Y => self.desired_len(ctx), @@ -48,7 +48,7 @@ impl Widget for Span { } } -impl Span { +impl Span { pub fn empty(dir: Dir) -> Self { Self { children: Vec::new(), @@ -62,7 +62,7 @@ impl Span { self } - fn len_sum(&mut self, ctx: &mut SizeCtx) -> Len { + fn len_sum(&mut self, ctx: &mut SizeCtx) -> Len { let gap = self.gap * self.children.len().saturating_sub(1) as f32; self.children.iter().fold(Len::abs(gap), |mut s, id| { // it's tempting to subtract the abs & rel from the ctx outer, @@ -78,7 +78,7 @@ impl Span { }) } - fn desired_len(&mut self, ctx: &mut SizeCtx) -> Len { + fn desired_len(&mut self, ctx: &mut SizeCtx) -> Len { let len = self.len_sum(ctx); if len.rest == 0.0 && len.rel == 0.0 { len @@ -87,7 +87,7 @@ impl Span { } } - fn desired_ortho(&mut self, ctx: &mut SizeCtx) -> Len { + fn desired_ortho(&mut self, ctx: &mut SizeCtx) -> Len { // this is a weird hack to get text wrapping to work properly when in a downward span // the correct solution here is to add a function to widget that lets them // request that ctx.outer has an axis "resolved" before checking the other, @@ -151,14 +151,14 @@ pub struct SpanBuilder, } -impl, Tag> FnOnce<(&mut Ui,)> +impl, Tag> FnOnce<(&mut State,)> for SpanBuilder { - type Output = Span; + type Output = Span; - extern "rust-call" fn call_once(self, args: (&mut Ui,)) -> Self::Output { + extern "rust-call" fn call_once(self, args: (&mut State,)) -> Self::Output { Span { - children: self.children.ui(args.0).arr.into_iter().collect(), + children: self.children.add(args.0).arr.into_iter().collect(), dir: self.dir, gap: self.gap, } @@ -183,15 +183,15 @@ impl, Tag> } } -impl std::ops::Deref for Span { - type Target = Vec>; +impl std::ops::Deref for Span { + type Target = Vec; fn deref(&self) -> &Self::Target { &self.children } } -impl std::ops::DerefMut for Span { +impl std::ops::DerefMut for Span { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.children } diff --git a/src/widget/position/stack.rs b/src/widget/position/stack.rs index f2a5d1c..ef0b4e7 100644 --- a/src/widget/position/stack.rs +++ b/src/widget/position/stack.rs @@ -2,13 +2,13 @@ use std::marker::PhantomData; use crate::prelude::*; -pub struct Stack { - pub children: Vec>, +pub struct Stack { + pub children: Vec, pub size: StackSize, } -impl Widget for Stack { - fn draw(&mut self, painter: &mut Painter) { +impl Widget for Stack { + fn draw(&mut self, painter: &mut Painter) { let mut iter = self.children.iter(); if let Some(child) = iter.next() { painter.child_layer(); @@ -20,14 +20,14 @@ impl Widget for Stack { } } - fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { + fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { match self.size { StackSize::Default => Len::default(), StackSize::Child(i) => ctx.width(&self.children[i]), } } - fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { + fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { match self.size { StackSize::Default => Len::default(), StackSize::Child(i) => ctx.height(&self.children[i]), @@ -48,14 +48,14 @@ pub struct StackBuilder, } -impl, Tag> FnOnce<(&mut Ui,)> +impl, Tag> FnOnce<(&mut State,)> for StackBuilder { - type Output = Stack; + type Output = Stack; - extern "rust-call" fn call_once(self, args: (&mut Ui,)) -> Self::Output { + extern "rust-call" fn call_once(self, args: (&mut State,)) -> Self::Output { Stack { - children: self.children.ui(args.0).arr.into_iter().collect(), + children: self.children.add(args.0).arr.into_iter().collect(), size: self.size, } } diff --git a/src/widget/ptr.rs b/src/widget/ptr.rs index b59736b..ebe8cb9 100644 --- a/src/widget/ptr.rs +++ b/src/widget/ptr.rs @@ -1,18 +1,18 @@ use crate::prelude::*; use std::marker::{Sized, Unsize}; -pub struct WidgetPtr { - pub inner: Option>, +pub struct WidgetPtr { + pub inner: Option, } -impl Widget for WidgetPtr { - fn draw(&mut self, painter: &mut Painter) { +impl Widget for WidgetPtr { + fn draw(&mut self, painter: &mut Painter) { if let Some(id) = &self.inner { painter.widget(id); } } - fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { + fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { if let Some(id) = &self.inner { ctx.width(id) } else { @@ -20,7 +20,7 @@ impl Widget for WidgetPtr { } } - fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { + fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { if let Some(id) = &self.inner { ctx.height(id) } else { @@ -29,7 +29,7 @@ impl Widget for WidgetPtr { } } -impl WidgetPtr { +impl WidgetPtr { pub fn new() -> Self { Self::default() } @@ -38,19 +38,19 @@ impl WidgetPtr { inner: Default::default(), } } - pub fn set>>(&mut self, to: WidgetHandle) { + pub fn set>(&mut self, to: WidgetHandle) { self.inner = Some(to) } - pub fn replace>>( + pub fn replace>( &mut self, - to: WidgetHandle, - ) -> Option> { + to: WidgetHandle, + ) -> Option { self.inner.replace(to) } } -impl Default for WidgetPtr { +impl Default for WidgetPtr { fn default() -> Self { Self::empty() } diff --git a/src/widget/rect.rs b/src/widget/rect.rs index 64a5596..f72820e 100644 --- a/src/widget/rect.rs +++ b/src/widget/rect.rs @@ -27,8 +27,8 @@ impl Rect { } } -impl Widget for Rect { - fn draw(&mut self, painter: &mut Painter) { +impl Widget for Rect { + fn draw(&mut self, painter: &mut Painter) { painter.primitive(RectPrimitive { color: self.color, radius: self.radius, @@ -37,11 +37,11 @@ impl Widget for Rect { }); } - fn desired_width(&mut self, _: &mut SizeCtx) -> Len { + fn desired_width(&mut self, _: &mut SizeCtx) -> Len { Len::rest(1) } - fn desired_height(&mut self, _: &mut SizeCtx) -> Len { + fn desired_height(&mut self, _: &mut SizeCtx) -> Len { Len::rest(1) } } diff --git a/src/widget/text/build.rs b/src/widget/text/build.rs index ee07c33..cedfab6 100644 --- a/src/widget/text/build.rs +++ b/src/widget/text/build.rs @@ -51,7 +51,7 @@ impl> TextBuilder { } } -impl TextBuilder { +impl TextBuilder { pub fn hint, Tag>( self, hint: W, @@ -59,7 +59,7 @@ impl TextBuilder { TextBuilder { content: self.content, attrs: self.attrs, - hint: move |ui: &mut Ui| Some(hint.add(ui).any()), + hint: move |ui: &mut State| Some(hint.add(ui).any()), output: self.output, state: PhantomData, } @@ -69,25 +69,25 @@ impl TextBuilder { pub trait TextBuilderOutput: Sized { type Output; fn run>( - ui: &mut Ui, + state: &mut State, builder: TextBuilder, ) -> Self::Output; } pub struct TextOutput; -impl TextBuilderOutput for TextOutput { - type Output = Text; +impl TextBuilderOutput for TextOutput { + type Output = Text; fn run>( - ui: &mut Ui, + state: &mut State, builder: TextBuilder, ) -> Self::Output { let mut buf = TextBuffer::new_empty(Metrics::new( builder.attrs.font_size, builder.attrs.line_height, )); - let hint = builder.hint.get(ui); - let font_system = &mut ui.text.font_system; + let hint = builder.hint.get(state); + let font_system = &mut state.ui().text.font_system; buf.set_text(font_system, &builder.content, &Attrs::new(), SHAPING, None); let mut text = Text { content: builder.content.into(), @@ -102,11 +102,12 @@ impl TextBuilderOutput for TextOutput { pub struct TextEditOutput { mode: EditMode, } -impl TextBuilderOutput for TextEditOutput { - type Output = TextEdit; + +impl TextBuilderOutput for TextEditOutput { + type Output = TextEdit; fn run>( - ui: &mut Ui, + state: &mut State, builder: TextBuilder, ) -> Self::Output { let buf = TextBuffer::new_empty(Metrics::new( @@ -114,10 +115,10 @@ impl TextBuilderOutput for TextEditOutput { builder.attrs.line_height, )); let mut text = TextEdit::new( - TextView::new(buf, builder.attrs, builder.hint.get(ui)), + TextView::new(buf, builder.attrs, builder.hint.get(state)), builder.output.mode, ); - let font_system = &mut ui.text.font_system; + let font_system = &mut state.ui().text.font_system; text.buf .set_text(font_system, &builder.content, &Attrs::new(), SHAPING, None); builder.attrs.apply(font_system, &mut text.buf, None); @@ -125,12 +126,12 @@ impl TextBuilderOutput for TextEditOutput { } } -impl, H: WidgetOption> FnOnce<(&mut Ui,)> +impl, H: WidgetOption> FnOnce<(&mut State,)> for TextBuilder { type Output = O::Output; - extern "rust-call" fn call_once(self, args: (&mut Ui,)) -> Self::Output { + extern "rust-call" fn call_once(self, args: (&mut State,)) -> Self::Output { O::run(args.0, self) } } diff --git a/src/widget/text/edit.rs b/src/widget/text/edit.rs index 67ec614..a09ed43 100644 --- a/src/widget/text/edit.rs +++ b/src/widget/text/edit.rs @@ -7,8 +7,8 @@ use winit::{ keyboard::{Key, NamedKey}, }; -pub struct TextEdit { - view: TextView, +pub struct TextEdit { + view: TextView, selection: TextSelection, history: Vec<(String, TextSelection)>, double_hit: Option, @@ -21,8 +21,8 @@ pub enum EditMode { MultiLine, } -impl TextEdit { - pub fn new(view: TextView, mode: EditMode) -> Self { +impl TextEdit { + pub fn new(view: TextView, mode: EditMode) -> Self { Self { view, selection: Default::default(), @@ -49,8 +49,8 @@ impl TextEdit { } } -impl Widget for TextEdit { - fn draw(&mut self, painter: &mut Painter) { +impl Widget for TextEdit { + fn draw(&mut self, painter: &mut Painter) { let base = painter.layer; painter.child_layer(); self.view.draw(painter); @@ -92,11 +92,11 @@ impl Widget for TextEdit { } } - fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { + fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { self.view.desired_width(ctx) } - fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { + fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { self.view.desired_height(ctx) } } @@ -180,12 +180,12 @@ fn cursor_pos(cursor: Cursor, buf: &TextBuffer) -> Option { prev } -pub struct TextEditCtx<'a, State> { - pub text: &'a mut TextEdit, +pub struct TextEditCtx<'a> { + pub text: &'a mut TextEdit, pub font_system: &'a mut FontSystem, } -impl<'a, State: 'static> TextEditCtx<'a, State> { +impl<'a> TextEditCtx<'a> { pub fn take(&mut self) -> String { let text = self .text @@ -602,26 +602,26 @@ impl TextInputResult { } } -impl Deref for TextEdit { - type Target = TextView; +impl Deref for TextEdit { + type Target = TextView; fn deref(&self) -> &Self::Target { &self.view } } -impl DerefMut for TextEdit { +impl DerefMut for TextEdit { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.view } } -pub trait TextEditable { - fn edit<'a>(&self, ui: &'a mut Ui) -> TextEditCtx<'a, State>; +pub trait TextEditable { + fn edit<'a>(&self, ui: &'a mut Ui) -> TextEditCtx<'a>; } -impl>> TextEditable for I { - fn edit<'a>(&self, ui: &'a mut Ui) -> TextEditCtx<'a, State> { +impl> TextEditable for I { + fn edit<'a>(&self, ui: &'a mut Ui) -> TextEditCtx<'a> { TextEditCtx { text: ui.widgets.get_mut(self).unwrap(), font_system: &mut ui.text.font_system, diff --git a/src/widget/text/mod.rs b/src/widget/text/mod.rs index b4d0760..54375a1 100644 --- a/src/widget/text/mod.rs +++ b/src/widget/text/mod.rs @@ -11,22 +11,22 @@ use std::ops::{Deref, DerefMut}; pub const SHAPING: Shaping = Shaping::Advanced; -pub struct Text { +pub struct Text { pub content: MutDetect, - view: TextView, + view: TextView, } -pub struct TextView { +pub struct TextView { pub attrs: MutDetect, pub buf: MutDetect, // cache tex: Option, width: Option, - pub hint: Option>, + pub hint: Option, } -impl TextView { - pub fn new(buf: TextBuffer, attrs: TextAttrs, hint: Option>) -> Self { +impl TextView { + pub fn new(buf: TextBuffer, attrs: TextAttrs, hint: Option) -> Self { Self { attrs: attrs.into(), buf: buf.into(), @@ -54,7 +54,7 @@ impl TextView { region } - fn render(&mut self, ctx: &mut SizeCtx) -> RenderedText { + fn render(&mut self, ctx: &mut SizeCtx) -> RenderedText { let width = if self.attrs.wrap { Some(ctx.px_size().x) } else { @@ -80,7 +80,7 @@ impl TextView { pub fn tex(&self) -> Option<&RenderedText> { self.tex.as_ref() } - pub fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { + pub fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { if let Some(hint) = &self.hint && let [line] = &self.buf.lines[..] && line.text().is_empty() @@ -90,7 +90,7 @@ impl TextView { Len::abs(self.render(ctx).size.x) } } - pub fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { + pub fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { if let Some(hint) = &self.hint && let [line] = &self.buf.lines[..] && line.text().is_empty() @@ -100,7 +100,7 @@ impl TextView { Len::abs(self.render(ctx).size.y) } } - pub fn draw(&mut self, painter: &mut Painter) -> UiRegion { + pub fn draw(&mut self, painter: &mut Painter) -> UiRegion { let tex = self.render(&mut painter.size_ctx()); let region = self.tex_region(&tex); if let Some(hint) = &self.hint @@ -124,7 +124,7 @@ impl TextView { } } -impl Text { +impl Text { pub fn new(content: impl Into) -> Self { let attrs = TextAttrs::default(); let buf = TextBuffer::new_empty(Metrics::new(attrs.font_size, attrs.line_height)); @@ -133,7 +133,7 @@ impl Text { view: TextView::new(buf, attrs, None), } } - fn update_buf(&mut self, ctx: &mut SizeCtx) { + fn update_buf(&mut self, ctx: &mut SizeCtx) { if self.content.changed { self.content.changed = false; self.view.buf.set_text( @@ -147,18 +147,18 @@ impl Text { } } -impl Widget for Text { - fn draw(&mut self, painter: &mut Painter) { +impl Widget for Text { + fn draw(&mut self, painter: &mut Painter) { self.update_buf(&mut painter.size_ctx()); self.view.draw(painter); } - fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { + fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { self.update_buf(ctx); self.view.desired_width(ctx) } - fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { + fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { self.update_buf(ctx); self.view.desired_height(ctx) } @@ -174,7 +174,7 @@ pub fn edit_line(line: &mut BufferLine, text: String) { line.set_text(text, line.ending(), line.attrs_list().clone()); } -impl Deref for Text { +impl Deref for Text { type Target = TextAttrs; fn deref(&self) -> &Self::Target { @@ -182,13 +182,13 @@ impl Deref for Text { } } -impl DerefMut for Text { +impl DerefMut for Text { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.view } } -impl Deref for TextView { +impl Deref for TextView { type Target = TextAttrs; fn deref(&self) -> &Self::Target { @@ -196,7 +196,7 @@ impl Deref for TextView { } } -impl DerefMut for TextView { +impl DerefMut for TextView { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.attrs } diff --git a/src/widget/trait_fns.rs b/src/widget/trait_fns.rs index e3b1bd2..10e4660 100644 --- a/src/widget/trait_fns.rs +++ b/src/widget/trait_fns.rs @@ -3,132 +3,132 @@ use crate::prelude::*; // these methods should "not require any context" (require unit) because they're in core widget_trait! { - pub trait CoreWidget; + pub trait CoreWidget; - fn pad(self, padding: impl Into) -> impl WidgetFn> { - |ui| Pad { + fn pad(self, padding: impl Into) -> impl WidgetFn { + |state| Pad { padding: padding.into(), - inner: self.add(ui), + inner: self.add(state), } } - fn align(self, align: impl Into) -> impl WidgetFn> { - move |ui| Aligned { - inner: self.add(ui), + fn align(self, align: impl Into) -> impl WidgetFn { + move |state| Aligned { + inner: self.add(state), align: align.into(), } } - fn center(self) -> impl WidgetFn> { + fn center(self) -> impl WidgetFn { self.align(Align::CENTER) } fn label(self, label: impl Into) -> impl WidgetIdFn { - |ui| { - let id = self.add(ui); - ui.set_label(&id, label.into()); + |state| { + let id = self.add(state); + state.ui().set_label(&id, label.into()); id } } - fn sized(self, size: impl Into) -> impl WidgetFn> { + fn sized(self, size: impl Into) -> impl WidgetFn { let size = size.into(); - move |ui| Sized { - inner: self.add(ui), + move |state| Sized { + inner: self.add(state), x: Some(size.x), y: Some(size.y), } } - fn max_width(self, len: impl Into) -> impl WidgetFn> { + fn max_width(self, len: impl Into) -> impl WidgetFn { let len = len.into(); - move |ui| MaxSize { - inner: self.add(ui), + move |state| MaxSize { + inner: self.add(state), x: Some(len), y: None, } } - fn max_height(self, len: impl Into) -> impl WidgetFn> { + fn max_height(self, len: impl Into) -> impl WidgetFn { let len = len.into(); - move |ui| MaxSize { - inner: self.add(ui), + move |state| MaxSize { + inner: self.add(state), x: None, y: Some(len), } } - fn width(self, len: impl Into) -> impl WidgetFn> { + fn width(self, len: impl Into) -> impl WidgetFn { let len = len.into(); - move |ui| Sized { - inner: self.add(ui), + move |state| Sized { + inner: self.add(state), x: Some(len), y: None, } } - fn height(self, len: impl Into) -> impl WidgetFn> { + fn height(self, len: impl Into) -> impl WidgetFn { let len = len.into(); - move |ui| Sized { - inner: self.add(ui), + move |state| Sized { + inner: self.add(state), x: None, y: Some(len), } } - fn offset(self, amt: impl Into) -> impl WidgetFn> { - move |ui| Offset { - inner: self.add(ui), + fn offset(self, amt: impl Into) -> impl WidgetFn { + move |state| Offset { + inner: self.add(state), amt: amt.into(), } } - fn scrollable(self) -> impl WidgetIdFn> { + fn scrollable(self) -> impl WidgetIdFn where State: HasEvents { use eventable::*; - move |ui| { - Scroll::new(self.add(ui), Axis::Y) + move |state| { + Scroll::new(self.add(state), Axis::Y) .on(CursorSense::Scroll, |mut ctx| { let delta = ctx.data.scroll_delta.y * 50.0; ctx.widget().scroll(delta); }) - .add(ui) + .add(state) } } - fn masked(self) -> impl WidgetFn> { - move |ui| Masked { - inner: self.add(ui), + fn masked(self) -> impl WidgetFn { + move |state| Masked { + inner: self.add(state), } } - fn background(self, w: impl WidgetLike) -> impl WidgetFn> { - move |ui| Stack { - children: vec![w.add(ui), self.add(ui)], + fn background(self, w: impl WidgetLike) -> impl WidgetFn { + move |state| Stack { + children: vec![w.add(state), self.add(state)], size: StackSize::Child(1), } } - fn foreground(self, w: impl WidgetLike) -> impl WidgetFn> { - move |ui| Stack { - children: vec![self.add(ui), w.add(ui)], + fn foreground(self, w: impl WidgetLike) -> impl WidgetFn { + move |state| Stack { + children: vec![self.add(state), w.add(state)], size: StackSize::Child(0), } } - fn layer_offset(self, offset: usize) -> impl WidgetFn> { - move |ui| LayerOffset { - inner: self.add(ui), + fn layer_offset(self, offset: usize) -> impl WidgetFn { + move |state| LayerOffset { + inner: self.add(state), offset, } } fn to_any(self) -> impl WidgetIdFn { - |ui| self.add(ui) + |state| self.add(state) } - fn set_ptr(self, ptr: WidgetRef>, ui: &mut Ui) { - let id = self.add(ui); - ui[ptr].inner = Some(id); + fn set_ptr(self, ptr: WidgetRef, state: &mut State) { + let id = self.add(state); + state.ui()[ptr].inner = Some(id); } }