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> {}
|
pub trait WidgetIdFn<Rsc, W: ?Sized = dyn Widget>: FnOnce(&mut Rsc) -> WidgetRef<W> {}
|
||||||
impl<State, W: ?Sized, F: FnOnce(&mut State) -> WidgetRef<W>> WidgetIdFn<State, W> for F {}
|
impl<Rsc, W: ?Sized, F: FnOnce(&mut Rsc) -> WidgetRef<W>> WidgetIdFn<Rsc, W> for F {}
|
||||||
|
|
||||||
pub trait IdLike {
|
pub trait IdLike {
|
||||||
type Widget: ?Sized;
|
type Widget: ?Sized;
|
||||||
|
|||||||
@@ -5,12 +5,14 @@ mod data;
|
|||||||
mod handle;
|
mod handle;
|
||||||
mod like;
|
mod like;
|
||||||
mod tag;
|
mod tag;
|
||||||
|
mod view;
|
||||||
mod widgets;
|
mod widgets;
|
||||||
|
|
||||||
pub use data::*;
|
pub use data::*;
|
||||||
pub use handle::*;
|
pub use handle::*;
|
||||||
pub use like::*;
|
pub use like::*;
|
||||||
pub use tag::*;
|
pub use tag::*;
|
||||||
|
pub use view::*;
|
||||||
pub use widgets::*;
|
pub use widgets::*;
|
||||||
|
|
||||||
pub trait Widget: Any {
|
pub trait Widget: Any {
|
||||||
|
|||||||
@@ -5,16 +5,16 @@ use std::marker::Unsize;
|
|||||||
pub struct WidgetTag;
|
pub struct WidgetTag;
|
||||||
impl<Rsc: HasUi, W: Widget> WidgetLike<Rsc, WidgetTag> for W {
|
impl<Rsc: HasUi, W: Widget> WidgetLike<Rsc, WidgetTag> for W {
|
||||||
type Widget = W;
|
type Widget = W;
|
||||||
fn add(self, state: &mut Rsc) -> WidgetRef<W> {
|
fn add(self, rsc: &mut Rsc) -> WidgetRef<W> {
|
||||||
state.ui_mut().widgets.add_weak(self)
|
rsc.ui_mut().widgets.add_weak(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FnTag;
|
pub struct FnTag;
|
||||||
impl<Rsc: HasUi, W: Widget, F: FnOnce(&mut Rsc) -> W> WidgetLike<Rsc, FnTag> for F {
|
impl<Rsc: HasUi, W: Widget, F: FnOnce(&mut Rsc) -> W> WidgetLike<Rsc, FnTag> for F {
|
||||||
type Widget = W;
|
type Widget = W;
|
||||||
fn add(self, state: &mut Rsc) -> WidgetRef<W> {
|
fn add(self, rsc: &mut Rsc) -> WidgetRef<W> {
|
||||||
self(state).add(state)
|
self(rsc).add(rsc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,26 +26,34 @@ pub struct FnTraitTag;
|
|||||||
impl<Rsc: HasUi, T: WidgetFnTrait<Rsc>> WidgetLike<Rsc, FnTraitTag> for T {
|
impl<Rsc: HasUi, T: WidgetFnTrait<Rsc>> WidgetLike<Rsc, FnTraitTag> for T {
|
||||||
type Widget = T::Widget;
|
type Widget = T::Widget;
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn add(self, state: &mut Rsc) -> WidgetRef<T::Widget> {
|
fn add(self, rsc: &mut Rsc) -> WidgetRef<T::Widget> {
|
||||||
self.run(state).add(state)
|
self.run(rsc).add(rsc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct IdTag;
|
pub struct RefTag;
|
||||||
impl<Rsc: HasUi, W: ?Sized + Widget + Unsize<dyn Widget>> WidgetLike<Rsc, IdTag> for WidgetRef<W> {
|
impl<Rsc: HasUi, W: ?Sized + Widget + Unsize<dyn Widget>> WidgetLike<Rsc, RefTag> for WidgetRef<W> {
|
||||||
type Widget = W;
|
type Widget = W;
|
||||||
fn add(self, _: &mut Rsc) -> WidgetRef<W> {
|
fn add(self, _: &mut Rsc) -> WidgetRef<W> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct IdFnTag;
|
pub struct RefFnTag;
|
||||||
impl<Rsc: HasUi, W: ?Sized + Widget + Unsize<dyn Widget>, F: FnOnce(&mut Rsc) -> WidgetRef<W>>
|
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;
|
type Widget = W;
|
||||||
fn add(self, state: &mut Rsc) -> WidgetRef<W> {
|
fn add(self, rsc: &mut Rsc) -> WidgetRef<W> {
|
||||||
self(state)
|
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| {
|
ctx.task.update(move |_, rsc| {
|
||||||
let rect = rect(rsc);
|
let rect = rect(rsc);
|
||||||
if rect.color == Color::RED {
|
if rect.color == Color::RED {
|
||||||
rect.color = Color::GREEN;
|
rect.color = Color::BLUE;
|
||||||
} else {
|
} else {
|
||||||
rect.color = Color::RED;
|
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()
|
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