widget view
This commit is contained in:
@@ -90,8 +90,8 @@ impl<W: ?Sized> Drop for WidgetHandle<W> {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait WidgetIdFn<State, W: ?Sized = dyn Widget>: FnOnce(&mut State) -> WidgetRef<W> {}
|
||||
impl<State, W: ?Sized, F: FnOnce(&mut State) -> WidgetRef<W>> WidgetIdFn<State, W> for F {}
|
||||
pub trait WidgetIdFn<Rsc, W: ?Sized = dyn Widget>: FnOnce(&mut Rsc) -> WidgetRef<W> {}
|
||||
impl<Rsc, W: ?Sized, F: FnOnce(&mut Rsc) -> WidgetRef<W>> WidgetIdFn<Rsc, W> for F {}
|
||||
|
||||
pub trait IdLike {
|
||||
type Widget: ?Sized;
|
||||
|
||||
@@ -5,12 +5,14 @@ mod data;
|
||||
mod handle;
|
||||
mod like;
|
||||
mod tag;
|
||||
mod view;
|
||||
mod widgets;
|
||||
|
||||
pub use data::*;
|
||||
pub use handle::*;
|
||||
pub use like::*;
|
||||
pub use tag::*;
|
||||
pub use view::*;
|
||||
pub use widgets::*;
|
||||
|
||||
pub trait Widget: Any {
|
||||
|
||||
@@ -5,16 +5,16 @@ use std::marker::Unsize;
|
||||
pub struct WidgetTag;
|
||||
impl<Rsc: HasUi, W: Widget> WidgetLike<Rsc, WidgetTag> for W {
|
||||
type Widget = W;
|
||||
fn add(self, state: &mut Rsc) -> WidgetRef<W> {
|
||||
state.ui_mut().widgets.add_weak(self)
|
||||
fn add(self, rsc: &mut Rsc) -> WidgetRef<W> {
|
||||
rsc.ui_mut().widgets.add_weak(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FnTag;
|
||||
impl<Rsc: HasUi, W: Widget, F: FnOnce(&mut Rsc) -> W> WidgetLike<Rsc, FnTag> for F {
|
||||
type Widget = W;
|
||||
fn add(self, state: &mut Rsc) -> WidgetRef<W> {
|
||||
self(state).add(state)
|
||||
fn add(self, rsc: &mut Rsc) -> WidgetRef<W> {
|
||||
self(rsc).add(rsc)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,26 +26,34 @@ pub struct FnTraitTag;
|
||||
impl<Rsc: HasUi, T: WidgetFnTrait<Rsc>> WidgetLike<Rsc, FnTraitTag> for T {
|
||||
type Widget = T::Widget;
|
||||
#[track_caller]
|
||||
fn add(self, state: &mut Rsc) -> WidgetRef<T::Widget> {
|
||||
self.run(state).add(state)
|
||||
fn add(self, rsc: &mut Rsc) -> WidgetRef<T::Widget> {
|
||||
self.run(rsc).add(rsc)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IdTag;
|
||||
impl<Rsc: HasUi, W: ?Sized + Widget + Unsize<dyn Widget>> WidgetLike<Rsc, IdTag> for WidgetRef<W> {
|
||||
pub struct RefTag;
|
||||
impl<Rsc: HasUi, W: ?Sized + Widget + Unsize<dyn Widget>> WidgetLike<Rsc, RefTag> for WidgetRef<W> {
|
||||
type Widget = W;
|
||||
fn add(self, _: &mut Rsc) -> WidgetRef<W> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IdFnTag;
|
||||
pub struct RefFnTag;
|
||||
impl<Rsc: HasUi, W: ?Sized + Widget + Unsize<dyn Widget>, F: FnOnce(&mut Rsc) -> WidgetRef<W>>
|
||||
WidgetLike<Rsc, IdFnTag> for F
|
||||
WidgetLike<Rsc, RefFnTag> for F
|
||||
{
|
||||
type Widget = W;
|
||||
fn add(self, state: &mut Rsc) -> WidgetRef<W> {
|
||||
self(state)
|
||||
fn add(self, rsc: &mut Rsc) -> WidgetRef<W> {
|
||||
self(rsc)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ViewTag;
|
||||
impl<Rsc: HasUi, V: WidgetView> WidgetLike<Rsc, ViewTag> for V {
|
||||
type Widget = V::Widget;
|
||||
fn add(self, _: &mut Rsc) -> WidgetRef<Self::Widget> {
|
||||
self.root()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
16
core/src/widget/view.rs
Normal file
16
core/src/widget/view.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
use std::marker::Unsize;
|
||||
|
||||
use crate::{Widget, WidgetRef};
|
||||
|
||||
pub trait WidgetView {
|
||||
type Widget: Widget + ?Sized + Unsize<dyn Widget>;
|
||||
fn root(&self) -> WidgetRef<Self::Widget>;
|
||||
}
|
||||
|
||||
pub trait HasWidget {
|
||||
type Widget: Widget + ?Sized + Unsize<dyn Widget>;
|
||||
}
|
||||
|
||||
impl<W: Widget + Unsize<dyn Widget>> HasWidget for WidgetRef<W> {
|
||||
type Widget = W;
|
||||
}
|
||||
@@ -18,7 +18,7 @@ impl DefaultAppState for State {
|
||||
ctx.task.update(move |_, rsc| {
|
||||
let rect = rect(rsc);
|
||||
if rect.color == Color::RED {
|
||||
rect.color = Color::GREEN;
|
||||
rect.color = Color::BLUE;
|
||||
} else {
|
||||
rect.color = Color::RED;
|
||||
}
|
||||
|
||||
46
examples/view.rs
Normal file
46
examples/view.rs
Normal file
@@ -0,0 +1,46 @@
|
||||
use iris::prelude::*;
|
||||
|
||||
fn main() {
|
||||
DefaultApp::<State>::run();
|
||||
}
|
||||
|
||||
#[derive(DefaultUiState)]
|
||||
struct State {
|
||||
ui_state: DefaultUiState,
|
||||
}
|
||||
|
||||
type Rsc = DefaultRsc<State>;
|
||||
|
||||
#[derive(Clone, Copy, WidgetView)]
|
||||
struct Test {
|
||||
#[root]
|
||||
root: WidgetRef<Rect>,
|
||||
}
|
||||
|
||||
impl Test {
|
||||
pub fn new(rsc: &mut Rsc) -> Self {
|
||||
let root = rect(Color::RED).add(rsc);
|
||||
Self { root }
|
||||
}
|
||||
pub fn toggle(&self, rsc: &mut Rsc) {
|
||||
let rect = (self.root)(rsc);
|
||||
if rect.color == Color::RED {
|
||||
rect.color = Color::BLUE;
|
||||
} else {
|
||||
rect.color = Color::RED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DefaultAppState for State {
|
||||
fn new(ui_state: DefaultUiState, rsc: &mut DefaultRsc<Self>, _: Proxy<Self::Event>) -> Self {
|
||||
let test = Test::new(rsc);
|
||||
|
||||
test.on(CursorSense::click(), move |_, rsc| {
|
||||
test.toggle(rsc);
|
||||
})
|
||||
.set_root(rsc);
|
||||
|
||||
Self { ui_state }
|
||||
}
|
||||
}
|
||||
@@ -151,3 +151,46 @@ pub fn derive_default_ui_state(input: TokenStream) -> TokenStream {
|
||||
});
|
||||
output.into()
|
||||
}
|
||||
|
||||
#[proc_macro_derive(WidgetView, attributes(root))]
|
||||
pub fn derive_widget_view(input: TokenStream) -> TokenStream {
|
||||
let mut output = proc_macro2::TokenStream::new();
|
||||
|
||||
let state: ItemStruct = parse_macro_input!(input);
|
||||
|
||||
let mut found_attr = false;
|
||||
let mut state_field = None;
|
||||
for field in &state.fields {
|
||||
let Some(attr) = field.attrs.iter().find(|a| a.path().is_ident("root")) else {
|
||||
continue;
|
||||
};
|
||||
if found_attr {
|
||||
output.extend(
|
||||
Error::new(attr.span(), "cannot have more than one root widget")
|
||||
.into_compile_error(),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
found_attr = true;
|
||||
state_field = Some(field);
|
||||
}
|
||||
let Some(field) = state_field else {
|
||||
output.extend(
|
||||
Error::new(state.ident.span(), "no root widget field found (#[root])")
|
||||
.into_compile_error(),
|
||||
);
|
||||
return output.into();
|
||||
};
|
||||
let sname = &state.ident;
|
||||
let fname = field.ident.as_ref().unwrap();
|
||||
let fty = &field.ty;
|
||||
output.extend(quote! {
|
||||
impl iris::core::WidgetView for #sname {
|
||||
type Widget = <#fty as iris::core::HasWidget>::Widget;
|
||||
fn root(&self) -> #fty {
|
||||
self.#fname
|
||||
}
|
||||
}
|
||||
});
|
||||
output.into()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user