diff --git a/core/src/attr.rs b/core/src/attr.rs index c9112ac..99d4151 100644 --- a/core/src/attr.rs +++ b/core/src/attr.rs @@ -1,24 +1,22 @@ -use crate::{HasUi, StateLike, WidgetIdFn, WidgetLike, WidgetRef}; +use crate::{HasUi, WidgetIdFn, WidgetLike, WidgetRef}; -pub trait WidgetAttr { +pub trait WidgetAttr { type Input; - fn run(state: &mut State, id: WidgetRef, input: Self::Input); + fn run(rsc: &mut Rsc, id: WidgetRef, input: Self::Input); } -pub trait Attrable { - fn attr>(self, input: A::Input) -> impl WidgetIdFn; +pub trait Attrable { + fn attr>(self, input: A::Input) -> impl WidgetIdFn; } -impl, WL: WidgetLike, Tag> - Attrable for WL -{ - fn attr>( +impl, Tag> Attrable for WL { + fn attr>( self, input: A::Input, - ) -> impl WidgetIdFn { - |state| { - let id = self.add(state); - A::run(state, id, input); + ) -> impl WidgetIdFn { + |rsc| { + let id = self.add(rsc); + A::run(rsc, id, input); id } } diff --git a/core/src/event/ctx.rs b/core/src/event/ctx.rs index d1a82bb..cf0005e 100644 --- a/core/src/event/ctx.rs +++ b/core/src/event/ctx.rs @@ -1,116 +1,18 @@ -use crate::{HasEvents, HasState, HasUi, StateLike, Ui, Widget, WidgetRef}; -use std::ops::{Deref, DerefMut}; +use crate::{HasEvents, HasUi, Widget, WidgetRef}; -pub struct EventCtx<'a, State, Data> { - pub state: &'a mut State, +pub struct EventCtx<'a, Rsc: HasEvents, Data> { + pub state: &'a mut Rsc::State, pub data: &'a mut Data, } -pub struct EventIdCtx<'a, State, Data, W: ?Sized> { +pub struct EventIdCtx<'a, Rsc: HasEvents, Data, W: ?Sized> { pub widget: WidgetRef, - pub state: &'a mut State, + pub state: &'a mut Rsc::State, pub data: &'a mut Data, } -impl Deref for EventIdCtx<'_, State, Data, W> { - type Target = State; - - fn deref(&self) -> &Self::Target { - self.state +impl EventIdCtx<'_, Rsc, Data, W> { + pub fn widget<'a>(&self, rsc: &'a mut Rsc) -> &'a mut W { + &mut rsc.ui_mut()[self.widget] } } - -impl DerefMut for EventIdCtx<'_, State, Data, W> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.state - } -} - -impl EventIdCtx<'_, State, Data, W> { - pub fn widget(&mut self) -> &mut W { - &mut self.state.get_mut()[self.widget] - } -} - -impl HasUi for EventIdCtx<'_, State, Data, W> { - fn get(&self) -> &Ui { - self.state.ui() - } - - fn get_mut(&mut self) -> &mut Ui { - self.state.ui_mut() - } -} - -impl HasState for EventIdCtx<'_, State, Data, W> { - type State = State; -} - -impl, Data, W: Widget> HasEvents - for EventIdCtx<'_, State, Data, W> -{ - fn get(&self) -> &super::EventManager { - self.state.events() - } - - fn get_mut(&mut self) -> &mut super::EventManager { - 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 0e737c3..1b08bc6 100644 --- a/core/src/event/manager.rs +++ b/core/src/event/manager.rs @@ -1,16 +1,16 @@ use crate::{ - ActiveData, Event, EventCtx, EventFn, EventIdCtx, EventLike, IdLike, LayerId, Widget, - WidgetEventFn, WidgetId, WidgetRef, + ActiveData, Event, EventCtx, EventFn, EventIdCtx, EventLike, HasEvents, IdLike, LayerId, + Widget, WidgetEventFn, WidgetId, WidgetRef, util::{HashMap, HashSet, TypeMap}, }; use std::{any::TypeId, rc::Rc}; -pub struct EventManager { +pub struct EventManager { widget_to_types: HashMap>, - types: TypeMap>, + types: TypeMap>, } -impl Default for EventManager { +impl Default for EventManager { fn default() -> Self { Self { widget_to_types: Default::default(), @@ -19,8 +19,8 @@ impl Default for EventManager { } } -impl EventManager { - pub fn get_type(&mut self) -> &mut TypeEventManager { +impl EventManager { + pub fn get_type(&mut self) -> &mut TypeEventManager { self.types.type_or_default() } @@ -28,7 +28,7 @@ impl EventManager { &mut self, id: WidgetRef, event: E, - f: impl for<'a> WidgetEventFn::Data<'a>, W>, + f: impl for<'a> WidgetEventFn::Data<'a>, W>, ) { self.get_type::().register(id, event, f); self.widget_to_types @@ -38,7 +38,7 @@ impl EventManager { } pub fn type_key() -> TypeId { - TypeId::of::>() + TypeId::of::>() } } @@ -48,7 +48,7 @@ pub trait EventsLike { fn undraw(&mut self, active: &ActiveData); } -impl EventsLike for EventManager { +impl EventsLike for EventManager { fn remove(&mut self, id: WidgetId) { for t in self.widget_to_types.get(&id).into_flat_iter() { self.types.get_mut(t).unwrap().remove(id); @@ -74,14 +74,14 @@ pub trait EventManagerLike { fn undraw(&mut self, data: &ActiveData); } -type EventData = (E, Rc EventFn::Data<'a>>>); -pub struct TypeEventManager { +type EventData = (E, Rc EventFn::Data<'a>>>); +pub struct TypeEventManager { // TODO: reduce visiblity!! pub active: HashMap>, - map: HashMap>>, + map: HashMap>>, } -impl EventManagerLike for TypeEventManager { +impl EventManagerLike for TypeEventManager { fn remove(&mut self, id: WidgetId) { self.map.remove(&id); for layer in self.active.values_mut() { @@ -102,7 +102,7 @@ impl EventManagerLike for TypeEventManager { } } -impl Default for TypeEventManager { +impl Default for TypeEventManager { fn default() -> Self { Self { active: Default::default(), @@ -111,23 +111,23 @@ impl Default for TypeEventManager { } } -impl TypeEventManager { +impl TypeEventManager { fn register( &mut self, widget: WidgetRef, event: impl EventLike, - f: impl for<'a> WidgetEventFn, W>, + f: impl for<'a> WidgetEventFn, W>, ) { let event = event.into_event(); self.map.entry(widget.id()).or_default().push(( event, - Rc::new(move |ctx| { + Rc::new(move |ctx, rsc| { let mut test = EventIdCtx { widget, state: ctx.state, data: ctx.data, }; - f(&mut test); + f(&mut test, rsc); }), )); } @@ -135,15 +135,18 @@ impl TypeEventManager { pub fn run_fn<'a>( &mut self, id: impl IdLike, - ) -> impl for<'b> FnOnce(EventCtx<'_, State, E::Data<'b>>) + 'a { + ) -> impl for<'b> FnOnce(EventCtx<'_, Rsc, E::Data<'b>>, &mut Rsc) + 'a { let fs = self.map.get(&id.id()).cloned().unwrap_or_default(); - move |ctx| { + move |ctx, rsc| { for (e, f) in fs { if e.should_run(ctx.data) { - f(&mut EventCtx { - state: ctx.state, - data: ctx.data, - }) + f( + &mut EventCtx { + state: ctx.state, + data: ctx.data, + }, + rsc, + ) } } } diff --git a/core/src/event/mod.rs b/core/src/event/mod.rs index 4223fab..1481eb2 100644 --- a/core/src/event/mod.rs +++ b/core/src/event/mod.rs @@ -28,14 +28,17 @@ impl EventLike for E { } } -pub trait EventFn: Fn(&mut EventCtx) + 'static {} -impl) + 'static, Data> EventFn for F {} +pub trait EventFn: Fn(&mut EventCtx, &mut Rsc) + 'static {} +impl, &mut Rsc) + 'static, Data> EventFn + for F +{ +} -pub trait WidgetEventFn: - Fn(&mut EventIdCtx) + 'static +pub trait WidgetEventFn: + Fn(&mut EventIdCtx, &mut Rsc) + 'static { } -impl) + 'static, Data, W: ?Sized> - WidgetEventFn for F +impl, &mut Rsc) + 'static, Data, W: ?Sized> + WidgetEventFn for F { } diff --git a/core/src/event/rsc.rs b/core/src/event/rsc.rs index 0da7214..b814bc9 100644 --- a/core/src/event/rsc.rs +++ b/core/src/event/rsc.rs @@ -2,40 +2,31 @@ use crate::{ Event, EventCtx, EventLike, EventManager, HasUi, IdLike, Widget, WidgetEventFn, WidgetRef, }; -pub trait HasState { - type State: HasUi; -} +pub trait HasEvents: Sized + HasUi + 'static { + type State; -pub trait HasEvents: Sized + HasState + HasUi { - fn get(&self) -> &EventManager; - fn get_mut(&mut self) -> &mut EventManager; - fn events(&self) -> &EventManager { - HasEvents::get(self) - } - fn events_mut(&mut self) -> &mut EventManager { - HasEvents::get_mut(self) - } + fn events(&self) -> &EventManager; + fn events_mut(&mut self) -> &mut EventManager; fn register_event( &mut self, id: WidgetRef, event: E, - f: impl for<'a> WidgetEventFn::Data<'a>, W>, - ) where - Self::State: 'static, - { + f: impl for<'a> WidgetEventFn::Data<'a>, W>, + ) { self.events_mut().register(id, event, f); } } -pub trait RunEvents: HasEvents + HasState + 'static { +pub trait RunEvents: HasEvents + 'static { fn run_event( &mut self, id: impl IdLike, data: &mut ::Data<'_>, + state: &mut Self::State, ) { let f = self.events_mut().get_type::().run_fn(id); - f(EventCtx { state: self, data }) + f(EventCtx { state, data }, self) } } -impl + 'static> RunEvents for T {} +impl RunEvents for T {} diff --git a/core/src/ui/mod.rs b/core/src/ui/mod.rs index bb5ecca..aa14ec7 100644 --- a/core/src/ui/mod.rs +++ b/core/src/ui/mod.rs @@ -42,22 +42,16 @@ pub struct Ui { } pub trait HasUi: Sized { - fn get(&self) -> &Ui; - fn get_mut(&mut self) -> &mut Ui; - fn ui(&self) -> &Ui { - self.get() - } - fn ui_mut(&mut self) -> &mut Ui { - self.get_mut() - } + fn ui(&self) -> &Ui; + fn ui_mut(&mut self) -> &mut Ui; } impl HasUi for Ui { - fn get(&self) -> &Ui { + fn ui(&self) -> &Ui { self } - fn get_mut(&mut self) -> &mut Ui { + fn ui_mut(&mut self) -> &mut Ui { self } } diff --git a/core/src/widget/like.rs b/core/src/widget/like.rs index 64e3061..5937f03 100644 --- a/core/src/widget/like.rs +++ b/core/src/widget/like.rs @@ -1,55 +1,45 @@ -use crate::{HasUi, Ui}; +use crate::HasUi; use super::*; use std::marker::Unsize; -pub trait StateLike { - fn as_state(&mut self) -> &mut State; -} - -impl StateLike for Ui { - fn as_state(&mut self) -> &mut Ui { - self - } -} - -pub trait WidgetLike, Tag>: Sized { +pub trait WidgetLike: Sized { type Widget: Widget + ?Sized + Unsize; - fn add(self, state: &mut impl StateLike) -> WidgetRef; + fn add(self, rsc: &mut Rsc) -> WidgetRef; - fn add_strong(self, state: &mut impl StateLike) -> WidgetHandle { - self.add(state).upgrade(state.as_state().ui_mut()) + fn add_strong(self, rsc: &mut Rsc) -> WidgetHandle { + self.add(rsc).upgrade(rsc.ui_mut()) } fn with_id( self, - f: impl FnOnce(&mut State, WidgetRef) -> WidgetRef, - ) -> impl WidgetIdFn { + f: impl FnOnce(&mut Rsc, WidgetRef) -> WidgetRef, + ) -> impl WidgetIdFn { move |state| { let id = self.add(state); f(state, id) } } - fn set_root(self, state: &mut impl StateLike) { + fn set_root(self, state: &mut Rsc) { let id = self.add(state); - let ui = state.as_state().ui_mut(); + let ui = state.ui_mut(); ui.root = Some(id.upgrade(ui)); } - fn handles(self, state: &mut impl StateLike) -> WidgetHandles { - self.add(state).upgrade(state.as_state().ui_mut()).handles() + fn handles(self, state: &mut Rsc) -> WidgetHandles { + self.add(state).upgrade(state.ui_mut()).handles() } } -pub trait WidgetArrLike { +pub trait WidgetArrLike { #[track_caller] - fn add(self, state: &mut impl StateLike) -> WidgetArr; + fn add(self, state: &mut Rsc) -> WidgetArr; } -impl WidgetArrLike for WidgetArr { - fn add(self, _: &mut impl StateLike) -> WidgetArr { +impl WidgetArrLike for WidgetArr { + fn add(self, _: &mut Rsc) -> WidgetArr { self } } @@ -60,12 +50,12 @@ macro_rules! impl_widget_arr { impl_widget_arr!($n;$($W)*;$(${concat($W,Tag)})*); }; ($n:expr;$($W:ident)*;$($Tag:ident)*) => { - impl, $($W: WidgetLike,$Tag,)*> WidgetArrLike for ($($W,)*) { - fn add(self, state: &mut impl StateLike) -> WidgetArr<$n> { + impl,$Tag,)*> WidgetArrLike for ($($W,)*) { + fn add(self, rsc: &mut Rsc) -> WidgetArr<$n> { #[allow(non_snake_case)] let ($($W,)*) = self; WidgetArr::new( - [$($W.add(state).upgrade(state.as_state().ui_mut()),)*], + [$($W.add(rsc).upgrade(rsc.ui_mut()),)*], ) } } diff --git a/core/src/widget/tag.rs b/core/src/widget/tag.rs index 9774949..27432fa 100644 --- a/core/src/widget/tag.rs +++ b/core/src/widget/tag.rs @@ -3,56 +3,49 @@ use crate::HasUi; use std::marker::Unsize; pub struct WidgetTag; -impl, W: Widget> WidgetLike for W { +impl WidgetLike for W { type Widget = W; - fn add(self, state: &mut impl StateLike) -> WidgetRef { - state.as_state().get_mut().widgets.add_weak(self) + fn add(self, state: &mut Rsc) -> WidgetRef { + state.ui_mut().widgets.add_weak(self) } } pub struct FnTag; -impl, W: Widget, F: FnOnce(&mut State) -> W> - WidgetLike for F -{ +impl W> WidgetLike for F { type Widget = W; - fn add(self, state: &mut impl StateLike) -> WidgetRef { - self(state.as_state()).add(state) + fn add(self, state: &mut Rsc) -> WidgetRef { + self(state).add(state) } } -pub trait WidgetFnTrait { +pub trait WidgetFnTrait { type Widget: Widget; - fn run(self, state: &mut State) -> Self::Widget; + fn run(self, rsc: &mut Rsc) -> Self::Widget; } pub struct FnTraitTag; -impl, T: WidgetFnTrait> WidgetLike for T { +impl> WidgetLike for T { type Widget = T::Widget; #[track_caller] - fn add(self, state: &mut impl StateLike) -> WidgetRef { - self.run(state.as_state()).add(state) + fn add(self, state: &mut Rsc) -> WidgetRef { + self.run(state).add(state) } } pub struct IdTag; -impl, W: ?Sized + Widget + Unsize> - WidgetLike for WidgetRef -{ +impl> WidgetLike for WidgetRef { type Widget = W; - fn add(self, _: &mut impl StateLike) -> WidgetRef { + fn add(self, _: &mut Rsc) -> WidgetRef { self } } pub struct IdFnTag; -impl< - State: HasUi + StateLike, - W: ?Sized + Widget + Unsize, - F: FnOnce(&mut State) -> WidgetRef, -> WidgetLike for F +impl, F: FnOnce(&mut Rsc) -> WidgetRef> + WidgetLike for F { type Widget = W; - fn add(self, state: &mut impl StateLike) -> WidgetRef { - self(state.as_state()) + fn add(self, state: &mut Rsc) -> WidgetRef { + self(state) } } diff --git a/examples/minimal.rs b/examples/minimal.rs index 5f1ef78..bfdf031 100644 --- a/examples/minimal.rs +++ b/examples/minimal.rs @@ -1,20 +1,17 @@ use iris::prelude::*; fn main() { - App::::run(); + DefaultApp::::run(); } -#[default_ui_state] -struct State {} +#[derive(DefaultUiState)] +struct State { + ui_state: DefaultUiState, +} impl DefaultAppState for State { - fn new(ui_state: DefaultUiState, _proxy: Proxy) -> Self { - let mut ui = Ui::new(); - rect(Color::RED).set_root(&mut ui); - Self { - ui, - ui_state, - events: EventManager::default(), - } + fn new(ui_state: DefaultUiState, rsc: &mut DefaultRsc, _: Proxy) -> Self { + rect(Color::RED).set_root(rsc); + Self { ui_state } } } diff --git a/macro/src/lib.rs b/macro/src/lib.rs index 0daa56a..4e859b1 100644 --- a/macro/src/lib.rs +++ b/macro/src/lib.rs @@ -2,8 +2,8 @@ extern crate proc_macro; use proc_macro::TokenStream; use quote::quote; use syn::{ - Attribute, Block, Error, Fields, FieldsNamed, GenericParam, Generics, Ident, ItemStruct, - ItemTrait, Meta, Signature, Token, Visibility, + Attribute, Block, Error, GenericParam, Generics, Ident, ItemStruct, ItemTrait, Signature, + Token, Type, Visibility, parse::{Parse, ParseStream, Result}, parse_macro_input, parse_quote, spanned::Spanned, @@ -89,104 +89,65 @@ pub fn widget_trait(input: TokenStream) -> TokenStream { quote! { #trai - impl #generics #name for WL { + impl #generics #name for WL { #(#impls)* } } .into() } -#[proc_macro_derive(UiState, attributes(rsc))] -pub fn derive_ui_state(input: TokenStream) -> TokenStream { +#[proc_macro_derive(DefaultUiState, attributes(default_ui_state))] +pub fn derive_default_ui_state(input: TokenStream) -> TokenStream { let mut output = proc_macro2::TokenStream::new(); let state: ItemStruct = parse_macro_input!(input); - let sname = state.ident; - let rscname = Ident::new(&(sname.to_string() + "Rsc"), sname.span()); - let mut rsc_fields = Vec::new(); - for field in state.fields { - let Some(attr) = field.attrs.iter().find(|a| a.path().is_ident("rsc")) else { + let mut found_attr = false; + let mut state_field = None; + for field in &state.fields { + if !found_attr + && let Type::Path(path) = &field.ty + && path.path.is_ident("DefaultUiState") + { + state_field = Some(field); + } + let Some(attr) = field + .attrs + .iter() + .find(|a| a.path().is_ident("default_ui_state")) + else { continue; }; - let Meta::List(list) = &attr.meta else { - output.extend(Error::new(attr.span(), "invalid attr syntax").into_compile_error()); + if found_attr { + output.extend( + Error::new( + attr.span(), + "cannot have more than one default_ui_state attribute", + ) + .into_compile_error(), + ); continue; - }; - let tname: Ident = match list.parse_args::() { - Ok(ident) => ident, - Err(err) => { - output.extend(err.to_compile_error()); - continue; - } - }; - let fty = &field.ty; - let fname = &field.ident.unwrap(); - rsc_fields.extend(quote! {#fname: #fty,}); - output.extend(quote! { - impl #tname for #sname { - fn get(&self) -> &#fty { - &self.#fname - } - fn get_mut(&mut self) -> &mut #fty { - &mut self.#fname - } - } - impl #tname for #rscname { - fn get(&self) -> &#fty { - &self.#fname - } - fn get_mut(&mut self) -> &mut #fty { - &mut self.#fname - } - } - }); + } + found_attr = true; + state_field = Some(field); } - let vis = state.vis; + let Some(field) = state_field else { + output.extend( + Error::new(state.ident.span(), "no DefaultUiState field found").into_compile_error(), + ); + return output.into(); + }; + let sname = &state.ident; + let fname = field.ident.as_ref().unwrap(); output.extend(quote! { - #vis struct #rscname { - #(#rsc_fields)* - } - - impl HasState for #sname { - type State = #sname; - } - - impl HasState for #rscname { - type State = #sname; - } - - impl StateLike<#sname> for #sname { - fn as_state(&mut self) -> &mut Self { - self + impl iris::default::HasDefaultUiState for #sname { + fn default_state(&self) -> &iris::default::DefaultUiState { + &self.#fname } - } - - impl StateLike<#rscname> for #rscname { - fn as_state(&mut self) -> &mut Self { - self + fn default_state_mut(&mut self) -> &mut iris::default::DefaultUiState { + &mut self.#fname } } }); output.into() } - -#[proc_macro_attribute] -pub fn default_ui_state(_attr: TokenStream, input: TokenStream) -> TokenStream { - let mut state: ItemStruct = parse_macro_input!(input); - let Fields::Named(fields) = &mut state.fields else { - panic!("must be on named fields struct"); - }; - let name = &state.ident; - state.attrs.push(parse_quote! {#[derive(UiState)]}); - let new: FieldsNamed = parse_quote! {{ - #[rsc(HasUi)] - pub ui: Ui, - #[rsc(HasDefaultUiState)] - pub ui_state: DefaultUiState, - #[rsc(HasEvents)] - pub events: iris::prelude::EventManager<#name>, - }}; - fields.named.extend(new.named); - quote! {#state}.into() -} diff --git a/src/bin/test/main.rs b/src/bin/test/main.rs index 4f0e197..6ee99fc 100644 --- a/src/bin/test/main.rs +++ b/src/bin/test/main.rs @@ -2,25 +2,20 @@ use cosmic_text::Family; use std::{cell::RefCell, rc::Rc}; use winit::event::WindowEvent; -iris::state_prelude!(ClientRsc); +iris::state_prelude!(DefaultRsc); fn main() { - App::::run(); + DefaultApp::::run(); } -#[default_ui_state] +#[derive(DefaultUiState)] pub struct Client { + ui_state: DefaultUiState, info: WidgetRef, } impl DefaultAppState for Client { - fn new(ui_state: DefaultUiState, _proxy: Proxy) -> Self { - let mut rsc = ClientRsc { - ui: Ui::new(), - ui_state, - events: EventManager::default(), - }; - + fn new(ui_state: DefaultUiState, rsc: &mut DefaultRsc, _: Proxy) -> Self { let rrect = rect(Color::WHITE).radius(20); let pad_test = ( rrect.color(Color::BLUE), @@ -43,7 +38,7 @@ impl DefaultAppState for Client { .width(rest(3)), ) .span(Dir::RIGHT) - .add(&mut rsc); + .add(rsc); let span_test = ( rrect.color(Color::GREEN).width(100), @@ -54,30 +49,30 @@ impl DefaultAppState for Client { rrect.color(Color::RED).width(100), ) .span(Dir::LEFT) - .add(&mut rsc); + .add(rsc); - let span_add = Span::empty(Dir::RIGHT).add(&mut rsc); + let span_add = Span::empty(Dir::RIGHT).add(rsc); let add_button = rect(Color::LIME) .radius(30) - .on(CursorSense::click(), move |ctx| { + .on(CursorSense::click(), move |_, rsc| { let child = image(include_bytes!("assets/sungals.png")) .center() - .add_strong(ctx); - span_add(ctx).push(child); + .add_strong(rsc); + span_add(rsc).push(child); }) .sized((150, 150)) .align(Align::BOT_RIGHT); let del_button = rect(Color::RED) .radius(30) - .on(CursorSense::click(), move |ctx| { - span_add(ctx).pop(); + .on(CursorSense::click(), move |_, rsc| { + span_add(rsc).pop(); }) .sized((150, 150)) .align(Align::BOT_LEFT); - let span_add_test = (span_add, add_button, del_button).stack().add(&mut rsc); + let span_add_test = (span_add, add_button, del_button).stack().add(rsc); let btext = |content| wtext(content).size(30); @@ -100,18 +95,18 @@ impl DefaultAppState for Client { wtext("pretty cool right?").size(50), ) .span(Dir::DOWN) - .add(&mut rsc); + .add(rsc); - let texts = Span::empty(Dir::DOWN).gap(10).add(&mut rsc); + let texts = Span::empty(Dir::DOWN).gap(10).add(rsc); let msg_area = texts.scrollable().masked().background(rect(Color::SKY)); let add_text = wtext("add") .editable(EditMode::MultiLine) .text_align(Align::LEFT) .size(30) .attr::(()) - .on(Submit, move |ctx| { + .on(Submit, move |ctx, rsc| { let w = ctx.widget; - let content = w.edit(ctx).take(); + let content = w.edit(rsc).take(); let text = wtext(content) .editable(EditMode::MultiLine) .size(30) @@ -120,10 +115,10 @@ impl DefaultAppState for Client { .attr::(()); let msg_box = text .background(rect(Color::WHITE.darker(0.5))) - .add_strong(ctx); - texts(ctx).push(msg_box); + .add_strong(rsc); + texts(rsc).push(msg_box); }) - .add(&mut rsc); + .add(rsc); let text_edit_scroll = ( msg_area.height(rest(1)), ( @@ -131,8 +126,8 @@ impl DefaultAppState for Client { ( add_text.width(rest(1)), Rect::new(Color::GREEN) - .on(CursorSense::click(), move |ctx| { - ctx.state.run_event::(add_text, &mut ()); + .on(CursorSense::click(), move |ctx, rsc| { + rsc.run_event::(add_text, &mut (), ctx.state); }) .sized((40, 40)), ) @@ -145,39 +140,39 @@ impl DefaultAppState for Client { .align(Align::BOT), ) .span(Dir::DOWN) - .add(&mut rsc); + .add(rsc); - let main = WidgetPtr::new().add(&mut rsc); + let main = WidgetPtr::new().add(rsc); let vals = Rc::new(RefCell::new((0, Vec::new()))); let mut switch_button = |color, to: WidgetRef, label| { - let to = to.upgrade(&mut rsc); + let to = to.upgrade(rsc); let vec = &mut vals.borrow_mut().1; let i = vec.len(); if vec.is_empty() { vec.push(None); - rsc.ui[main].set(to); + main(rsc).set(to); } else { vec.push(Some(to)); } let vals = vals.clone(); let rect = rect(color) - .on(CursorSense::click(), move |ctx| { + .on(CursorSense::click(), move |ctx, rsc| { let (prev, vec) = &mut *vals.borrow_mut(); if let Some(h) = vec[i].take() { - vec[*prev] = main(ctx).replace(h); + vec[*prev] = main(rsc).replace(h); *prev = i; } - ctx.widget().color = color.darker(0.3); + ctx.widget(rsc).color = color.darker(0.3); }) .on( CursorSense::HoverStart | CursorSense::unclick(), - move |ctx| { - ctx.widget().color = color.brighter(0.2); + move |ctx, rsc| { + ctx.widget(rsc).color = color.brighter(0.2); }, ) - .on(CursorSense::HoverEnd, move |ctx| { - ctx.widget().color = color; + .on(CursorSense::HoverEnd, move |ctx, rsc| { + ctx.widget(rsc).color = color; }); (rect, wtext(label).size(30).text_align(Align::CENTER)).stack() }; @@ -195,30 +190,25 @@ impl DefaultAppState for Client { ) .span(Dir::RIGHT); - let info = wtext("").add(&mut rsc); + let info = wtext("").add(rsc); let info_sect = info.pad(10).align(Align::RIGHT); ((tabs.height(40), main.pad(10)).span(Dir::DOWN), info_sect) .stack() - .set_root(&mut rsc); + .set_root(rsc); - Self { - ui: rsc.ui, - ui_state: rsc.ui_state, - events: rsc.events, - info, - } + Self { ui_state, info } } - fn window_event(&mut self, _: WindowEvent) { + fn window_event(&mut self, _: WindowEvent, rsc: &mut DefaultRsc) { let new = format!( - "widgets: {}\nactive:{}\nviews: {}", - self.ui.num_widgets(), - self.ui.active_widgets(), + "widgets: {}\nactive: {}\nviews: {}", + rsc.ui.num_widgets(), + rsc.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 != *rsc.ui[self.info].content { + *rsc.ui[self.info].content = new; } } } diff --git a/src/default/app.rs b/src/default/app.rs index 700a2bc..fe8dfaa 100644 --- a/src/default/app.rs +++ b/src/default/app.rs @@ -11,6 +11,13 @@ pub trait AppState { fn window_event(&mut self, event: WindowEvent, event_loop: &ActiveEventLoop); fn event(&mut self, event: Self::Event, event_loop: &ActiveEventLoop); fn exit(&mut self); + + fn run() + where + Self: Sized, + { + App::::run(); + } } pub struct App { diff --git a/src/default/attr.rs b/src/default/attr.rs index 47f08da..fc0f933 100644 --- a/src/default/attr.rs +++ b/src/default/attr.rs @@ -4,35 +4,36 @@ use winit::dpi::{LogicalPosition, LogicalSize}; pub struct Selector; -impl WidgetAttr for Selector +impl WidgetAttr for Selector where - State::State: HasDefaultUiState, + Rsc::State: HasDefaultUiState, { type Input = WidgetRef; - fn run(state: &mut State, container: WidgetRef, id: Self::Input) { - state.register_event(container, CursorSense::click_or_drag(), move |ctx| { - let region = ctx.ui().window_region(&id).unwrap(); + fn run(rsc: &mut Rsc, container: WidgetRef, id: Self::Input) { + rsc.register_event(container, CursorSense::click_or_drag(), move |ctx, rsc| { + let region = rsc.ui().window_region(&id).unwrap(); let id_pos = region.top_left; - let container_pos = ctx.state.ui().window_region(&container).unwrap().top_left; + let container_pos = rsc.ui().window_region(&container).unwrap().top_left; let pos = ctx.data.pos + container_pos - id_pos; let size = region.size(); - select(ctx.state, id, pos, size, ctx.data.sense.is_dragging()); + select(rsc, ctx.state, id, pos, size, ctx.data.sense.is_dragging()); }); } } pub struct Selectable; -impl WidgetAttr for Selectable +impl WidgetAttr for Selectable where - State::State: HasDefaultUiState, + Rsc::State: HasDefaultUiState, { type Input = (); - fn run(state: &mut State, id: WidgetRef, _: Self::Input) { - state.register_event(id, CursorSense::click_or_drag(), move |ctx| { + fn run(rsc: &mut Rsc, id: WidgetRef, _: Self::Input) { + rsc.register_event(id, CursorSense::click_or_drag(), move |ctx, rsc| { select( + rsc, ctx.state, id, ctx.data.pos, @@ -44,18 +45,19 @@ where } fn select( + rsc: &mut impl HasUi, state: &mut impl HasDefaultUiState, id: WidgetRef, pos: Vec2, size: Vec2, dragging: bool, ) { - let (ui, state) = HasDefaultUiState::ui_with_state(state); + let state = state.default_state_mut(); let now = Instant::now(); let recent = (now - state.last_click) < Duration::from_millis(300); state.last_click = now; - id.edit(ui).select(pos, size, dragging, recent); - if let Some(region) = ui.window_region(&id) { + id.edit(rsc).select(pos, size, dragging, recent); + if let Some(region) = rsc.ui().window_region(&id) { state.window.set_ime_allowed(true); state.window.set_ime_cursor_area( LogicalPosition::::from(region.top_left.tuple()), diff --git a/src/default/mod.rs b/src/default/mod.rs index a69536e..ee526d2 100644 --- a/src/default/mod.rs +++ b/src/default/mod.rs @@ -1,7 +1,10 @@ use crate::prelude::*; use arboard::Clipboard; -use iris_core::util::forget_mut; -use std::{marker::Sized, sync::Arc, time::Instant}; +use std::{ + marker::{PhantomData, Sized}, + sync::Arc, + time::Instant, +}; use winit::{ event::{Ime, WindowEvent}, event_loop::{ActiveEventLoop, EventLoopProxy}, @@ -49,53 +52,97 @@ impl DefaultUiState { } } -pub trait HasDefaultUiState: Sized + 'static + HasUi { - fn get(&self) -> &DefaultUiState; - fn get_mut(&mut self) -> &mut DefaultUiState; - fn ui_state(&self) -> &DefaultUiState { - HasDefaultUiState::get(self) - } - fn ui_state_mut(&mut self) -> &mut DefaultUiState { - HasDefaultUiState::get_mut(self) - } - fn ui_with_state(&mut self) -> (&mut Ui, &mut DefaultUiState) { - // as long as you're not doing anything actually unhinged this should always work safely - ( - unsafe { forget_mut(self.ui_mut()) }, - HasDefaultUiState::get_mut(self), - ) - } +pub trait HasAppEvent { + type Event: 'static; } -pub trait DefaultAppState: RunEvents + HasDefaultUiState { - type Event: 'static = (); - fn new(ui_state: DefaultUiState, proxy: Proxy) -> Self; +impl HasAppEvent for T { + type Event = (); +} + +pub trait HasDefaultUiState: Sized + 'static + HasAppEvent { + fn default_state(&self) -> &DefaultUiState; + fn default_state_mut(&mut self) -> &mut DefaultUiState; +} + +pub trait DefaultAppState: HasDefaultUiState { + fn new(ui_state: DefaultUiState, rsc: &mut DefaultRsc, proxy: Proxy) + -> Self; #[allow(unused_variables)] - fn event(&mut self, event: Self::Event) {} + fn event(&mut self, event: Self::Event, rsc: &mut DefaultRsc) {} #[allow(unused_variables)] - fn exit(&mut self) {} + fn exit(&mut self, rsc: &mut DefaultRsc) {} #[allow(unused_variables)] - fn window_event(&mut self, event: WindowEvent) {} + fn window_event(&mut self, event: WindowEvent, rsc: &mut DefaultRsc) {} fn window_attributes() -> WindowAttributes { Default::default() } } -impl AppState for State { +pub struct DefaultRsc { + pub ui: Ui, + pub events: EventManager, + _state: PhantomData, +} + +impl Default for DefaultRsc { + fn default() -> Self { + Self { + ui: Default::default(), + events: Default::default(), + _state: Default::default(), + } + } +} + +impl HasUi for DefaultRsc { + fn ui(&self) -> &Ui { + &self.ui + } + + fn ui_mut(&mut self) -> &mut Ui { + &mut self.ui + } +} + +impl HasEvents for DefaultRsc { + type State = State; + + fn events(&self) -> &EventManager { + &self.events + } + + fn events_mut(&mut self) -> &mut EventManager { + &mut self.events + } +} + +pub struct DefaultApp { + rsc: DefaultRsc, + state: State, +} + +// impl StateLike for DefaultRsc { +// } +// +impl AppState for DefaultApp { type Event = State::Event; fn new(event_loop: &ActiveEventLoop, proxy: EventLoopProxy) -> Self { - let window = event_loop.create_window(Self::window_attributes()).unwrap(); - Self::new(DefaultUiState::new(window), proxy) + let window = event_loop + .create_window(State::window_attributes()) + .unwrap(); + let mut rsc = DefaultRsc::default(); + let state = State::new(DefaultUiState::new(window), &mut rsc, proxy); + Self { rsc, state } } fn event(&mut self, event: Self::Event, _: &ActiveEventLoop) { - self.event(event); + self.state.event(event, &mut self.rsc); } fn window_event(&mut self, event: WindowEvent, event_loop: &ActiveEventLoop) { - let events = unsafe { forget_mut(self.events_mut()) }; - let ui_state = HasDefaultUiState::get_mut(self); + let ui_state = self.state.default_state_mut(); let input_changed = ui_state.input.event(&event); let cursor_state = ui_state.cursor_state().clone(); let old = ui_state.focus; @@ -104,9 +151,11 @@ impl AppState for State { } if input_changed { let window_size = ui_state.window_size(); - self.run_sensors(&cursor_state, window_size); + self.rsc + .run_sensors(&mut self.state, &cursor_state, window_size); } - let (mut ui, mut ui_state) = self.ui_with_state(); + let ui = &mut self.rsc.ui; + let ui_state = self.state.default_state_mut(); if old != ui_state.focus && let Some(old) = old { @@ -115,7 +164,7 @@ impl AppState for State { match &event { WindowEvent::CloseRequested => event_loop.exit(), WindowEvent::RedrawRequested => { - ui.update(events); + ui.update(&mut self.rsc.events); ui_state.renderer.update(ui); ui_state.renderer.draw(); } @@ -134,13 +183,13 @@ impl AppState for State { ui_state.window.set_ime_allowed(false); } TextInputResult::Submit => { - self.run_event::(sel, &mut ()); + self.rsc.run_event::(sel, &mut (), &mut self.state); } TextInputResult::Paste => { if let Ok(t) = ui_state.clipboard.get_text() { text.insert(&t); } - self.run_event::(sel, &mut ()); + self.rsc.run_event::(sel, &mut (), &mut self.state); } TextInputResult::Copy(text) => { if let Err(err) = ui_state.clipboard.set_text(text) { @@ -148,7 +197,7 @@ impl AppState for State { } } TextInputResult::Used => { - self.run_event::(sel, &mut ()); + self.rsc.run_event::(sel, &mut (), &mut self.state); } TextInputResult::Unused => {} } @@ -172,15 +221,15 @@ impl AppState for State { } _ => (), } - self.window_event(event); - (ui, ui_state) = self.ui_with_state(); - if ui.needs_redraw() { + self.state.window_event(event, &mut self.rsc); + let ui_state = self.state.default_state_mut(); + if self.rsc.ui.needs_redraw() { ui_state.renderer.window().request_redraw(); } ui_state.input.end_frame(); } fn exit(&mut self) { - self.exit(); + self.state.exit(&mut self.rsc); } } diff --git a/src/default/sense.rs b/src/default/sense.rs index 446c395..871cf48 100644 --- a/src/default/sense.rs +++ b/src/default/sense.rs @@ -115,7 +115,7 @@ pub enum ActivationState { /// or basically have some way to have custom senses /// that depend on active widget positions /// but I'm not sure how or if worth it -pub struct Sensor { +pub struct Sensor { pub senses: CursorSenses, pub f: Rc>, } @@ -138,12 +138,12 @@ pub struct CursorData<'a> { pub sense: CursorSense, } -pub trait SensorUi { - fn run_sensors(&mut self, cursor: &CursorState, window_size: Vec2); +pub trait SensorUi { + fn run_sensors(&mut self, state: &mut Rsc::State, cursor: &CursorState, window_size: Vec2); } -impl SensorUi for State { - fn run_sensors(&mut self, cursor: &CursorState, window_size: Vec2) { +impl SensorUi for Rsc { + fn run_sensors(&mut self, state: &mut Rsc::State, cursor: &CursorState, window_size: Vec2) { let layers = std::mem::take(&mut self.ui_mut().layers); let mut active = std::mem::take(&mut self.events_mut().get_type::().active); for layer in layers.indices().rev() { @@ -168,7 +168,7 @@ impl SensorUi for State { // might wanna set up Event to have a prepare stage sense: CursorSense::Hovering, }; - self.run_event::(*id, &mut data); + self.run_event::(*id, &mut data, state); } if sensed { break; diff --git a/src/event.rs b/src/event.rs index 6f92a7d..9d4cfe7 100644 --- a/src/event.rs +++ b/src/event.rs @@ -3,20 +3,20 @@ use crate::prelude::*; pub mod eventable { use super::*; widget_trait! { - pub trait Eventable + 'static>; + pub trait Eventable; fn on( self, event: E, - f: impl for<'a> WidgetEventFn::Data<'a>, WL::Widget>, - ) -> impl WidgetIdFn { + f: impl for<'a> WidgetEventFn::Data<'a>, WL::Widget>, + ) -> impl WidgetIdFn { move |state| { let id = self.add(state); - state.register_event(id, event.into_event(), move |ctx| { + state.register_event(id, event.into_event(), move |ctx, rsc| { f(&mut EventIdCtx { widget: id, state: ctx.state, data: ctx.data, - }); + }, rsc); }); id } diff --git a/src/typed.rs b/src/typed.rs index f3792aa..4f4b1cd 100644 --- a/src/typed.rs +++ b/src/typed.rs @@ -1,36 +1,36 @@ #[macro_export] macro_rules! event_state { - ($vis:vis $state:ty) => { + ($vis:vis $rsc:ty) => { mod local_event_trait { use super::*; #[allow(unused_imports)] use $crate::prelude::*; - pub trait EventableCtx, Tag> { + pub trait EventableCtx, Tag> { fn on( self, event: E, f: impl for<'a> WidgetEventFn< - <$state as HasState>::State, + $rsc, ::Data<'a>, WL::Widget >, - ) -> impl WidgetIdFn<$state, WL::Widget>; + ) -> impl WidgetIdFn<$rsc, WL::Widget>; } - impl, Tag> EventableCtx for WL { + impl, Tag> EventableCtx for WL { fn on( self, event: E, f: impl for<'a> WidgetEventFn< - <$state as HasState>::State, + $rsc, ::Data<'a>, WL::Widget >, - ) -> impl WidgetIdFn<$state, WL::Widget> { + ) -> impl WidgetIdFn<$rsc, WL::Widget> { eventable::Eventable::on(self, event, f) } } } - $vis type EventManager = $crate::prelude::EventManager<<$state as HasState>::State>; + $vis type EventManager = $crate::prelude::EventManager<<$rsc as HasEvents>::State>; $vis use local_event_trait::*; }; } diff --git a/src/widget/image.rs b/src/widget/image.rs index 0c3e9ce..d90b743 100644 --- a/src/widget/image.rs +++ b/src/widget/image.rs @@ -22,7 +22,7 @@ impl Widget for Image { pub fn image(image: impl LoadableImage) -> impl WidgetFn { let image = image.get_image().expect("Failed to load image"); move |state| Image { - handle: state.get_mut().add_texture(image), + handle: state.ui_mut().add_texture(image), } } diff --git a/src/widget/position/span.rs b/src/widget/position/span.rs index 7431b46..9c4c802 100644 --- a/src/widget/position/span.rs +++ b/src/widget/position/span.rs @@ -159,15 +159,15 @@ pub struct SpanBuilder, } -impl, const LEN: usize, Wa: WidgetArrLike, Tag> - WidgetFnTrait for SpanBuilder +impl, Tag> WidgetFnTrait + for SpanBuilder { type Widget = Span; #[track_caller] - fn run(self, state: &mut State) -> Self::Widget { + fn run(self, rsc: &mut Rsc) -> Self::Widget { Span { - children: self.children.add(state).arr.into_iter().collect(), + children: self.children.add(rsc).arr.into_iter().collect(), dir: self.dir, gap: self.gap, } diff --git a/src/widget/position/stack.rs b/src/widget/position/stack.rs index 087243a..44f751a 100644 --- a/src/widget/position/stack.rs +++ b/src/widget/position/stack.rs @@ -48,14 +48,15 @@ pub struct StackBuilder, } -impl, const LEN: usize, Wa: WidgetArrLike, Tag> FnOnce<(&mut State,)> - for StackBuilder +impl, Tag> WidgetFnTrait + for StackBuilder { - type Output = Stack; + type Widget = Stack; - extern "rust-call" fn call_once(self, args: (&mut State,)) -> Self::Output { + #[track_caller] + fn run(self, rsc: &mut Rsc) -> Self::Widget { Stack { - children: self.children.add(args.0).arr.into_iter().collect(), + children: self.children.add(rsc).arr.into_iter().collect(), size: self.size, } } diff --git a/src/widget/text/build.rs b/src/widget/text/build.rs index 9bc225f..7f8f255 100644 --- a/src/widget/text/build.rs +++ b/src/widget/text/build.rs @@ -51,15 +51,15 @@ impl> TextBuilder { } } -impl, O> TextBuilder { - pub fn hint, Tag>( +impl TextBuilder { + pub fn hint, Tag>( self, hint: W, - ) -> TextBuilder> { + ) -> TextBuilder> { TextBuilder { content: self.content, attrs: self.attrs, - hint: move |ui: &mut State| Some(hint.add_strong(ui).any()), + hint: move |rsc: &mut Rsc| Some(hint.add_strong(rsc).any()), output: self.output, state: PhantomData, } @@ -75,19 +75,19 @@ pub trait TextBuilderOutput: Sized { } pub struct TextOutput; -impl TextBuilderOutput for TextOutput { +impl TextBuilderOutput for TextOutput { type Output = Text; - fn run>( - state: &mut State, - builder: TextBuilder, + fn run>( + state: &mut Rsc, + 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(state); - let font_system = &mut state.get_mut().text.font_system; + let font_system = &mut state.ui_mut().text.font_system; buf.set_text(font_system, &builder.content, &Attrs::new(), SHAPING, None); let mut text = Text { content: builder.content.into(), @@ -118,7 +118,7 @@ impl TextBuilderOutput for TextEditOutput { TextView::new(buf, builder.attrs, builder.hint.get(state)), builder.output.mode, ); - let font_system = &mut state.get_mut().text.font_system; + let font_system = &mut state.ui_mut().text.font_system; text.buf .set_text(font_system, &builder.content, &Attrs::new(), SHAPING, None); builder.attrs.apply(font_system, &mut text.buf, None); diff --git a/src/widget/trait_fns.rs b/src/widget/trait_fns.rs index a4bd893..a6e4500 100644 --- a/src/widget/trait_fns.rs +++ b/src/widget/trait_fns.rs @@ -3,35 +3,35 @@ use crate::prelude::*; // these methods should "not require any context" (require unit) because they're in core widget_trait! { - pub trait CoreWidget + 'static>; + pub trait CoreWidget; - fn pad(self, padding: impl Into) -> impl WidgetFn { + fn pad(self, padding: impl Into) -> impl WidgetFn { |state| Pad { padding: padding.into(), inner: self.add_strong(state), } } - fn align(self, align: impl Into) -> impl WidgetFn { + fn align(self, align: impl Into) -> impl WidgetFn { move |state| Aligned { inner: self.add_strong(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 { + fn label(self, label: impl Into) -> impl WidgetIdFn { |state| { let id = self.add(state); - state.get_mut().set_label(id, label.into()); + state.ui_mut().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 |state| Sized { inner: self.add_strong(state), @@ -40,7 +40,7 @@ widget_trait! { } } - fn max_width(self, len: impl Into) -> impl WidgetFn { + fn max_width(self, len: impl Into) -> impl WidgetFn { let len = len.into(); move |state| MaxSize { inner: self.add_strong(state), @@ -49,7 +49,7 @@ widget_trait! { } } - fn max_height(self, len: impl Into) -> impl WidgetFn { + fn max_height(self, len: impl Into) -> impl WidgetFn { let len = len.into(); move |state| MaxSize { inner: self.add_strong(state), @@ -58,7 +58,7 @@ widget_trait! { } } - fn width(self, len: impl Into) -> impl WidgetFn { + fn width(self, len: impl Into) -> impl WidgetFn { let len = len.into(); move |state| Sized { inner: self.add_strong(state), @@ -67,7 +67,7 @@ widget_trait! { } } - fn height(self, len: impl Into) -> impl WidgetFn { + fn height(self, len: impl Into) -> impl WidgetFn { let len = len.into(); move |state| Sized { inner: self.add_strong(state), @@ -76,59 +76,59 @@ widget_trait! { } } - fn offset(self, amt: impl Into) -> impl WidgetFn { + fn offset(self, amt: impl Into) -> impl WidgetFn { move |state| Offset { inner: self.add_strong(state), amt: amt.into(), } } - fn scrollable(self) -> impl WidgetIdFn where State: HasEvents { + fn scrollable(self) -> impl WidgetIdFn where Rsc: HasEvents { use eventable::*; move |state| { Scroll::new(self.add_strong(state), Axis::Y) - .on(CursorSense::Scroll, |ctx: &mut EventIdCtx<'_, State::State, CursorData<'_>, Scroll>| { + .on(CursorSense::Scroll, |ctx, rsc| { let delta = ctx.data.scroll_delta.y * 50.0; - ctx.widget().scroll(delta); + ctx.widget(rsc).scroll(delta); }) .add(state) } } - fn masked(self) -> impl WidgetFn { + fn masked(self) -> impl WidgetFn { move |state| Masked { inner: self.add_strong(state), } } - fn background(self, w: impl WidgetLike) -> impl WidgetFn { + fn background(self, w: impl WidgetLike) -> impl WidgetFn { move |state| Stack { children: vec![w.add_strong(state), self.add_strong(state)], size: StackSize::Child(1), } } - fn foreground(self, w: impl WidgetLike) -> impl WidgetFn { + fn foreground(self, w: impl WidgetLike) -> impl WidgetFn { move |state| Stack { children: vec![self.add_strong(state), w.add_strong(state)], size: StackSize::Child(0), } } - fn layer_offset(self, offset: usize) -> impl WidgetFn { + fn layer_offset(self, offset: usize) -> impl WidgetFn { move |state| LayerOffset { inner: self.add_strong(state), offset, } } - fn to_any(self) -> impl WidgetIdFn { + fn to_any(self) -> impl WidgetIdFn { |state| self.add(state) } - fn set_ptr(self, ptr: WidgetRef, state: &mut State) { + fn set_ptr(self, ptr: WidgetRef, state: &mut Rsc) { let id = self.add_strong(state); - state.get_mut()[ptr].inner = Some(id); + state.ui_mut()[ptr].inner = Some(id); } }