mirror of
https://github.com/danbulant/mangui
synced 2026-05-19 03:58:34 +00:00
working reactivity in components
This commit is contained in:
parent
327a13147d
commit
1870d6e65e
4 changed files with 138 additions and 12 deletions
|
|
@ -2,7 +2,7 @@ use rusalka_macro::make_component;
|
|||
use std::default::Default;
|
||||
use mangui::{SharedNode, nodes::Style, taffy::prelude::Size, femtovg::{Paint, Color}, nodes::layout::Layout};
|
||||
|
||||
use rusalka::nodes::primitives::{Rectangle, RectangleAttributes};
|
||||
use rusalka::nodes::primitives::{Rectangle, RectangleAttributes, PartialRectangleAttributes};
|
||||
|
||||
make_component!(
|
||||
ComponentDemo,
|
||||
|
|
@ -16,7 +16,7 @@ make_component!(
|
|||
test_: bool = false
|
||||
}
|
||||
Reactive {
|
||||
dbg!($test_);
|
||||
// dbg!($test_);
|
||||
}
|
||||
Component {
|
||||
@layout {
|
||||
|
|
@ -28,11 +28,9 @@ make_component!(
|
|||
match event.event {
|
||||
mangui::events::InnerEvent::MouseDown(_) => {
|
||||
$test_ = true;
|
||||
println!("Mouse down");
|
||||
},
|
||||
mangui::events::InnerEvent::MouseUp(_) => {
|
||||
$test_ = false;
|
||||
println!("Mouse up");
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,11 @@ fn main() {
|
|||
}));
|
||||
let groot: SharedNode = Arc::new(RwLock::new(root));
|
||||
|
||||
let cdemo: Arc<Mutex<component_demo_syntax::ComponentDemo>> = Arc::new_cyclic(|cself| Mutex::new(component_demo_syntax::ComponentDemo::new(component_demo_syntax::ComponentDemoAttributes { radius: 10. }, cself.clone())));
|
||||
let cdemo: Arc<Mutex<component_demo_syntax::ComponentDemo>> = Arc::new_cyclic(|cself|
|
||||
Mutex::new(component_demo_syntax::ComponentDemo::new(component_demo_syntax::ComponentDemoAttributes {
|
||||
radius: 15.
|
||||
}, cself.clone()))
|
||||
);
|
||||
cdemo.lock().unwrap().mount(&groot, None);
|
||||
|
||||
mangui::run_event_loop(MainEntry {
|
||||
|
|
|
|||
|
|
@ -39,13 +39,14 @@ struct ComponentUsed {
|
|||
parent: Option<usize>,
|
||||
component_type: ComponentType,
|
||||
event_listeners: Vec<EventListener>,
|
||||
reactive_props: HashMap<Ident, ReactiveBlock>
|
||||
reactive_props: HashMap<String, ReactiveBlock>
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ReactiveBlock {
|
||||
variables: Vec<Ident>,
|
||||
contents: TokenStream
|
||||
contents: TokenStream,
|
||||
prop_ident: Option<Ident>
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
|
|
@ -202,7 +203,8 @@ pub fn make_component(item: TokenStream) -> TokenStream {
|
|||
let (variables, contents) = replace_variables(group.stream());
|
||||
reactive_blocks.push(ReactiveBlock {
|
||||
variables,
|
||||
contents
|
||||
contents,
|
||||
prop_ident: None
|
||||
});
|
||||
},
|
||||
"Component" => {
|
||||
|
|
@ -606,8 +608,8 @@ pub fn make_component(item: TokenStream) -> TokenStream {
|
|||
|
||||
set_stream_inner.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Bracket, to_update_stream))));
|
||||
|
||||
set_stream_inner.extend(TokenStream::from(quote!(|= 1 <<)));
|
||||
set_stream_inner.extend(Some(TokenTree::Literal(Literal::u32_unsuffixed(i % 32))));
|
||||
set_stream_inner.extend(TokenStream::from(quote!(|= )));
|
||||
set_stream_inner.extend(Some(TokenTree::Literal(Literal::u32_unsuffixed(1 << i % 32))));
|
||||
|
||||
set_stream.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Brace, set_stream_inner))));
|
||||
|
||||
|
|
@ -807,6 +809,87 @@ pub fn make_component(item: TokenStream) -> TokenStream {
|
|||
update_stream.extend(Some(TokenTree::Group(inner_group)));
|
||||
}
|
||||
|
||||
let mut component_index = 0;
|
||||
'block: for component in &components_used {
|
||||
for (prop, block) in &component.reactive_props {
|
||||
let mut keys: Vec<u32> = vec![0; all_variables.len() / 32 + 1];
|
||||
for variable in &block.variables {
|
||||
let index = all_variables.iter().position(|x| x.name.to_string() == variable.to_string());
|
||||
if let None = index {
|
||||
eprintln!("Warning: variable {} not found in component {}", variable, name);
|
||||
continue 'block;
|
||||
}
|
||||
let index = index.unwrap();
|
||||
let array_offset = index / 32;
|
||||
let num_offset = index % 32;
|
||||
*keys.get_mut(array_offset).unwrap() |= 1 << num_offset;
|
||||
}
|
||||
update_stream.extend(TokenStream::from(quote!(if)));
|
||||
|
||||
let mut i = 0;
|
||||
for key in keys {
|
||||
if i > 0 {
|
||||
update_stream.extend(TokenStream::from(quote!(||)));
|
||||
}
|
||||
update_stream.extend(TokenStream::from(quote!(bitmap)));
|
||||
let mut ifgroup_stream = TokenStream::new();
|
||||
// update_stream.extend(Some(TokenTree::Literal(Literal::u32_unsuffixed(key))));
|
||||
ifgroup_stream.extend(Some(TokenTree::Literal(Literal::u32_unsuffixed(i))));
|
||||
update_stream.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Bracket, ifgroup_stream))));
|
||||
update_stream.extend(TokenStream::from(quote!(&)));
|
||||
update_stream.extend(Some(TokenTree::Literal(Literal::u32_unsuffixed(key))));
|
||||
update_stream.extend(TokenStream::from(quote!(!= 0)));
|
||||
i += 1;
|
||||
}
|
||||
|
||||
let mut inner_stream = TokenStream::new();
|
||||
|
||||
match component.component_type {
|
||||
ComponentType::Node => {
|
||||
inner_stream.extend(TokenStream::from(quote!(self.)));
|
||||
inner_stream.extend(Some(TokenTree::Ident(Ident::new(&format!("comp{}", component_index), Span::call_site()))));
|
||||
inner_stream.extend(TokenStream::from(quote!(.write().unwrap().)));
|
||||
inner_stream.extend(Some(TokenTree::Ident(block.prop_ident.clone().unwrap())));
|
||||
inner_stream.extend(TokenStream::from(quote!( = )));
|
||||
inner_stream.extend(replace_variables(block.contents.clone()).1);
|
||||
},
|
||||
ComponentType::RealComponent => {
|
||||
inner_stream.extend(TokenStream::from(quote!(self.)));
|
||||
inner_stream.extend(Some(TokenTree::Ident(Ident::new(&format!("comp{}", component_index), Span::call_site()))));
|
||||
inner_stream.extend(TokenStream::from(quote!(.lock().unwrap().set)));
|
||||
|
||||
let mut component_set_stream = TokenStream::new();
|
||||
|
||||
component_set_stream.extend(Some(TokenTree::Ident(block.prop_ident.clone().unwrap())));
|
||||
component_set_stream.extend(TokenStream::from(quote!(: Option::Some)));
|
||||
|
||||
let component_set_some_stream = replace_variables(block.contents.clone()).1;
|
||||
|
||||
let mut component_set_group = Group::new(proc_macro::Delimiter::Parenthesis, component_set_some_stream);
|
||||
component_set_stream.extend(Some(TokenTree::Group(component_set_group)));
|
||||
|
||||
component_set_stream.extend(TokenStream::from(quote!(, ..Default::default())));
|
||||
|
||||
let component_set_group = Group::new(proc_macro::Delimiter::Brace, component_set_stream);
|
||||
let mut component_set_outer_stream = TokenStream::new();
|
||||
|
||||
let name = component.name.clone().to_string();
|
||||
|
||||
component_set_outer_stream.extend(Some(TokenTree::Ident(Ident::new(&format!("Partial{}Attributes", name), Span::call_site()))));
|
||||
|
||||
component_set_outer_stream.extend(Some(TokenTree::Group(component_set_group)));
|
||||
let component_set_outer_group = Group::new(proc_macro::Delimiter::Parenthesis, component_set_outer_stream);
|
||||
|
||||
inner_stream.extend(Some(TokenTree::Group(component_set_outer_group)));
|
||||
}
|
||||
}
|
||||
|
||||
let inner_group = Group::new(proc_macro::Delimiter::Brace, inner_stream);
|
||||
update_stream.extend(Some(TokenTree::Group(inner_group)));
|
||||
}
|
||||
component_index += 1;
|
||||
}
|
||||
|
||||
let update_group = Group::new(proc_macro::Delimiter::Brace, update_stream);
|
||||
component_impl_stream.extend(Some(TokenTree::Group(update_group)));
|
||||
|
||||
|
|
@ -1051,12 +1134,54 @@ fn parse_components(name: Ident, group: Group, next: usize, parent: Option<usize
|
|||
_ => panic!("Expected group after |param|")
|
||||
};
|
||||
|
||||
let this_component = components_found.get_mut(next).unwrap();
|
||||
let this_component = components_found.get_mut(0).unwrap();
|
||||
this_component.event_listeners.push(EventListener {
|
||||
callback: fn_group,
|
||||
identifier: fn_param
|
||||
});
|
||||
},
|
||||
TokenTree::Ident(ident) => {
|
||||
let ident_str = ident.to_string();
|
||||
self_stream.extend(Some(TokenTree::Ident(ident.clone())));
|
||||
let nexttoken = group.next();
|
||||
match nexttoken {
|
||||
None => {},
|
||||
Some(token) => match token {
|
||||
TokenTree::Punct(punct) if punct.as_char() == ':' => {
|
||||
self_stream.extend(Some(TokenTree::Punct(punct)));
|
||||
// likely reactive property
|
||||
let mut property_stream = TokenStream::new();
|
||||
while let Some(token) = group.next() {
|
||||
match token {
|
||||
TokenTree::Punct(punct) => {
|
||||
let char = punct.as_char();
|
||||
property_stream.extend(Some(TokenTree::Punct(punct)));
|
||||
if char == ',' {
|
||||
break;
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
property_stream.extend(Some(token));
|
||||
}
|
||||
}
|
||||
}
|
||||
let (reactive_variables, property_stream) = replace_variables(property_stream);
|
||||
if reactive_variables.len() > 0 {
|
||||
let this_component = components_found.get_mut(0).unwrap();
|
||||
this_component.reactive_props.insert(ident_str, ReactiveBlock {
|
||||
variables: reactive_variables,
|
||||
contents: property_stream.clone(),
|
||||
prop_ident: Some(ident)
|
||||
});
|
||||
}
|
||||
self_stream.extend(property_stream);
|
||||
},
|
||||
_ => {
|
||||
self_stream.extend(Some(token));
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
any => {
|
||||
// skip until next ',', writing to self_stream
|
||||
self_stream.extend(Some(any));
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ impl Component for Rectangle {
|
|||
let mut to_update = [0; Self::UPDATE_LENGTH];
|
||||
if let Some(radius) = attrs.radius {
|
||||
self.attrs.radius = radius;
|
||||
dbg!("Radius set", radius);
|
||||
to_update[0] |= 1;
|
||||
}
|
||||
if to_update.into_iter().reduce(|a,b| a+b).unwrap() != 0 {
|
||||
|
|
|
|||
Loading…
Reference in a new issue