diff --git a/core/src/attr.rs b/core/src/attr.rs index d90b6c3..df64a0f 100644 --- a/core/src/attr.rs +++ b/core/src/attr.rs @@ -1,4 +1,4 @@ -use crate::{HasUi, WidgetIdFn, WidgetLike, WidgetRef}; +use crate::{HasUi, StateLike, WidgetIdFn, WidgetLike, WidgetRef}; pub trait WidgetAttr { type Input; @@ -9,7 +9,9 @@ pub trait Attrable { fn attr>(self, input: A::Input) -> impl WidgetIdFn; } -impl, Tag> Attrable for WL { +impl, WL: WidgetLike, Tag> + Attrable for WL +{ fn attr>( self, input: A::Input, diff --git a/core/src/event/ctx.rs b/core/src/event/ctx.rs index 1b8969e..d1a82bb 100644 --- a/core/src/event/ctx.rs +++ b/core/src/event/ctx.rs @@ -1,4 +1,4 @@ -use crate::{HasEvents, HasState, HasUi, Ui, Widget, WidgetRef}; +use crate::{HasEvents, HasState, HasUi, StateLike, Ui, Widget, WidgetRef}; use std::ops::{Deref, DerefMut}; pub struct EventCtx<'a, State, Data> { @@ -26,7 +26,7 @@ impl DerefMut for EventIdCtx<'_, State, Data, W> } } -impl<'a, State: HasUi, Data, W: Widget> EventIdCtx<'a, State, Data, W> { +impl EventIdCtx<'_, State, Data, W> { pub fn widget(&mut self) -> &mut W { &mut self.state.get_mut()[self.widget] } @@ -57,3 +57,60 @@ impl, Data, W: Widget> HasEvents self.state.events_mut() } } + +impl StateLike for EventIdCtx<'_, State, Data, W> { + fn as_state(&mut self) -> &mut State { + self.state + } +} + +// fn test() { +// use crate::*; +// struct ClientRsc; +// impl HasUi for EventCtx<'_, State, Data> { +// fn get(&self) -> &Ui { +// todo!() +// } +// +// fn get_mut(&mut self) -> &mut Ui { +// todo!() +// } +// } +// fn on(_: impl for<'a> EventFn) {} +// +// pub trait WidgetLike: Sized { +// type Widget: Widget + ?Sized + std::marker::Unsize; +// +// fn add(self, state: &mut State) -> WidgetHandle; +// +// fn with_id( +// self, +// f: impl FnOnce(&mut State, WidgetHandle) -> WidgetHandle, +// ) -> impl WidgetIdFn { +// move |state| { +// let id = self.add(state); +// f(state, id) +// } +// } +// +// fn set_root(self, state: &mut State) { +// state.get_mut().root = Some(self.add(state)); +// } +// +// fn handles(self, state: &mut State) -> WidgetHandles { +// self.add(state).handles() +// } +// } +// +// pub struct WidgetTag; +// impl WidgetLike for W { +// type Widget = W; +// fn add(self, state: &mut State) -> WidgetHandle { +// state.get_mut().add_widget(self) +// } +// } +// +// on(move |ctx| { +// ().add(ctx); +// }); +// } diff --git a/core/src/event/manager.rs b/core/src/event/manager.rs index 14a05c2..1c49664 100644 --- a/core/src/event/manager.rs +++ b/core/src/event/manager.rs @@ -116,11 +116,12 @@ impl TypeEventManager { self.map.entry(widget.id()).or_default().push(( event, Rc::new(move |ctx| { - f(&mut EventIdCtx { + let mut test = EventIdCtx { widget, state: ctx.state, data: ctx.data, - }); + }; + f(&mut test); }), )); } @@ -128,7 +129,7 @@ impl TypeEventManager { pub fn run_fn<'a>( &mut self, id: impl IdLike, - ) -> impl for<'b> FnOnce(EventCtx>) + 'a { + ) -> impl for<'b> FnOnce(EventCtx<'_, State, E::Data<'b>>) + 'a { let fs = self.map.get(&id.id()).cloned().unwrap_or_default(); move |ctx| { for (e, f) in fs { diff --git a/core/src/widget/like.rs b/core/src/widget/like.rs index 7841149..dac20f6 100644 --- a/core/src/widget/like.rs +++ b/core/src/widget/like.rs @@ -1,12 +1,22 @@ -use crate::HasUi; +use crate::{HasUi, Ui}; use super::*; use std::marker::Unsize; -pub trait WidgetLike: Sized { - type Widget: Widget + ?Sized + Unsize + 'static; +pub trait StateLike { + fn as_state(&mut self) -> &mut State; +} - fn add(self, state: &mut State) -> WidgetHandle; +impl StateLike for Ui { + fn as_state(&mut self) -> &mut Ui { + self + } +} + +pub trait WidgetLike, Tag>: Sized { + type Widget: Widget + ?Sized + Unsize; + + fn add(self, state: &mut impl StateLike) -> WidgetHandle; fn with_id( self, @@ -18,21 +28,21 @@ pub trait WidgetLike: Sized { } } - fn set_root(self, state: &mut State) { - state.get_mut().root = Some(self.add(state)); + fn set_root(self, state: &mut impl StateLike) { + state.as_state().get_mut().root = Some(self.add(state)); } - fn handles(self, state: &mut State) -> WidgetHandles { + fn handles(self, state: &mut impl StateLike) -> WidgetHandles { self.add(state).handles() } } pub trait WidgetArrLike { - fn add(self, state: &mut State) -> WidgetArr; + fn add(self, state: &mut impl StateLike) -> WidgetArr; } impl WidgetArrLike for WidgetArr { - fn add(self, _: &mut State) -> WidgetArr { + fn add(self, _: &mut impl StateLike) -> WidgetArr { self } } @@ -43,8 +53,8 @@ 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 add(self, state: &mut State) -> WidgetArr<$n> { + impl, $($W: WidgetLike,$Tag,)*> WidgetArrLike for ($($W,)*) { + fn add(self, state: &mut impl StateLike) -> WidgetArr<$n> { #[allow(non_snake_case)] let ($($W,)*) = self; WidgetArr::new( diff --git a/core/src/widget/tag.rs b/core/src/widget/tag.rs index fa30cc4..899dea0 100644 --- a/core/src/widget/tag.rs +++ b/core/src/widget/tag.rs @@ -1,46 +1,46 @@ +use super::*; +use crate::HasUi; use std::marker::Unsize; -use crate::HasUi; - -use super::*; - -pub struct ArrTag; - pub struct WidgetTag; -impl WidgetLike for W { +impl, W: Widget> WidgetLike for W { type Widget = W; - fn add(self, state: &mut State) -> WidgetHandle { - state.get_mut().add_widget(self) + fn add(self, state: &mut impl StateLike) -> WidgetHandle { + state.as_state().get_mut().add_widget(self) } } pub struct FnTag; -impl W> WidgetLike for F { +impl, W: Widget, F: FnOnce(&mut State) -> W> + WidgetLike for F +{ type Widget = W; - fn add(self, state: &mut State) -> WidgetHandle { - self(state).add(state) + fn add(self, state: &mut impl StateLike) -> WidgetHandle { + self(state.as_state()).add(state) } } pub struct IdTag; -impl + 'static> +impl, W: ?Sized + Widget + Unsize> WidgetLike for WidgetHandle { type Widget = W; - fn add(self, _: &mut State) -> WidgetHandle { + fn add(self, _: &mut impl StateLike) -> WidgetHandle { self } } pub struct IdFnTag; impl< - State: HasUi + 'static, - W: ?Sized + Widget + Unsize + 'static, + State: HasUi + StateLike, + W: ?Sized + Widget + Unsize, F: FnOnce(&mut State) -> WidgetHandle, > WidgetLike for F { type Widget = W; - fn add(self, state: &mut State) -> WidgetHandle { - self(state) + fn add(self, state: &mut impl StateLike) -> WidgetHandle { + self(state.as_state()) } } + +pub struct ArrTag; diff --git a/macro/src/lib.rs b/macro/src/lib.rs index 43ab00b..0daa56a 100644 --- a/macro/src/lib.rs +++ b/macro/src/lib.rs @@ -155,6 +155,18 @@ pub fn derive_ui_state(input: TokenStream) -> TokenStream { impl HasState for #rscname { type State = #sname; } + + impl StateLike<#sname> for #sname { + fn as_state(&mut self) -> &mut Self { + self + } + } + + impl StateLike<#rscname> for #rscname { + fn as_state(&mut self) -> &mut Self { + self + } + } }); output.into() } diff --git a/src/bin/test/main.rs b/src/bin/test/main.rs index c6b3848..e252901 100644 --- a/src/bin/test/main.rs +++ b/src/bin/test/main.rs @@ -64,7 +64,7 @@ impl DefaultAppState for Client { .on(CursorSense::click(), move |ctx| { let child = image(include_bytes!("assets/sungals.png")) .center() - .add(ctx.state); + .add(ctx); (span_add.r)(ctx).children.push(child); }) .sized((150, 150)) @@ -119,9 +119,7 @@ impl DefaultAppState for Client { .text_align(Align::LEFT) .wrap(true) .attr::(()); - let msg_box = text - .background(rect(Color::WHITE.darker(0.5))) - .add(ctx.state); + let msg_box = text.background(rect(Color::WHITE.darker(0.5))).add(ctx); (texts.r)(ctx).children.push(msg_box); }) .handles(&mut rsc); diff --git a/src/event.rs b/src/event.rs index 876a145..3b17a2d 100644 --- a/src/event.rs +++ b/src/event.rs @@ -3,7 +3,7 @@ use crate::prelude::*; pub mod eventable { use super::*; widget_trait! { - pub trait Eventable; + pub trait Eventable + 'static>; fn on( self, event: E, diff --git a/src/widget/position/span.rs b/src/widget/position/span.rs index 09ec245..eef6c6f 100644 --- a/src/widget/position/span.rs +++ b/src/widget/position/span.rs @@ -151,7 +151,7 @@ pub struct SpanBuilder, } -impl, Tag> FnOnce<(&mut State,)> +impl, const LEN: usize, Wa: WidgetArrLike, Tag> FnOnce<(&mut State,)> for SpanBuilder { type Output = Span; diff --git a/src/widget/position/stack.rs b/src/widget/position/stack.rs index ef0b4e7..087243a 100644 --- a/src/widget/position/stack.rs +++ b/src/widget/position/stack.rs @@ -48,7 +48,7 @@ pub struct StackBuilder, } -impl, Tag> FnOnce<(&mut State,)> +impl, const LEN: usize, Wa: WidgetArrLike, Tag> FnOnce<(&mut State,)> for StackBuilder { type Output = Stack; diff --git a/src/widget/text/build.rs b/src/widget/text/build.rs index 1f97193..b91b43d 100644 --- a/src/widget/text/build.rs +++ b/src/widget/text/build.rs @@ -51,7 +51,7 @@ impl> TextBuilder { } } -impl TextBuilder { +impl, O> TextBuilder { pub fn hint, Tag>( self, hint: W, diff --git a/src/widget/trait_fns.rs b/src/widget/trait_fns.rs index f87bcce..9663158 100644 --- a/src/widget/trait_fns.rs +++ b/src/widget/trait_fns.rs @@ -3,7 +3,7 @@ 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 + 'static>; fn pad(self, padding: impl Into) -> impl WidgetFn { |state| Pad {