rusalka: progress on reactivity, native nodes support

This commit is contained in:
Daniel Bulant 2023-10-30 20:13:25 +01:00
parent 38473da15f
commit 3d6ac6cdcf
7 changed files with 418 additions and 94 deletions

View file

@ -1,32 +1,59 @@
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex, RwLock};
use mangui::SharedNode; use mangui::{SharedNode, nodes::{layout::Layout, Style}, taffy::prelude::Size};
use rusalka::{component::Component, nodes::primitives::{Rectangle, RectangleAttributes}, SharedComponent}; use rusalka::{component::Component, nodes::{primitives::{Rectangle, RectangleAttributes}, insert, detach}, SharedComponent};
pub struct DemoComponent { pub struct DemoComponent {
rect: SharedComponent<Rectangle>, rect: SharedComponent<Rectangle>,
attrs: DemoComponentAttributes, attrs: DemoComponentAttributes,
layout: Arc<RwLock<Layout>>
} }
#[derive(Default)]
pub struct DemoComponentAttributes {} pub struct DemoComponentAttributes {}
#[derive(Default)]
pub struct PartialDemoComponentAttributes {}
impl From<DemoComponentAttributes> for PartialDemoComponentAttributes {
fn from(_attrs: DemoComponentAttributes) -> Self {
Self {}
}
}
impl Component for DemoComponent { impl Component for DemoComponent {
type ComponentAttrs = DemoComponentAttributes; type ComponentAttrs = DemoComponentAttributes;
type PartialComponentAttrs = PartialDemoComponentAttributes;
fn new(attrs: Self::ComponentAttrs) -> Self { fn new(attrs: Self::ComponentAttrs) -> Self {
Self { Self {
rect: Arc::new(Mutex::new(Rectangle::new(RectangleAttributes {}))), rect: Arc::new(Mutex::new(Rectangle::new(RectangleAttributes { ..Default::default() }))),
layout: Arc::new(RwLock::new(Layout {
style: Style {
layout: mangui::nodes::TaffyStyle {
min_size: Size {
width: mangui::taffy::style::Dimension::Points(50.),
height: mangui::taffy::style::Dimension::Points(100.)
},
..Default::default()
},
..Default::default()
},
..Default::default()
})),
attrs, attrs,
} }
} }
fn set(&mut self, attrs: Self::ComponentAttrs) { self.attrs = attrs; } fn set(&mut self, _attrs: Self::PartialComponentAttrs) { }
fn get(&self) -> &Self::ComponentAttrs { &self.attrs } fn get(&self) -> &Self::ComponentAttrs { &self.attrs }
fn mount(&self, parent: &SharedNode, before: Option<&SharedNode>) { fn mount(&self, parent: &SharedNode, before: Option<&SharedNode>) {
self.rect.lock().unwrap().mount(parent, before); insert(parent, &{self.layout.clone()}, before);
self.rect.lock().unwrap().mount(&{self.layout.clone()}, None);
} }
fn unmount(&self) { fn unmount(&self) {
self.rect.lock().unwrap().unmount(); self.rect.lock().unwrap().unmount();
detach(&{self.layout.clone()});
} }
fn update(&self) {} fn update(&self, _bitmap: &[u32]) {}
} }

View file

@ -1,29 +1,21 @@
use rusalka_macro::make_component; use rusalka_macro::make_component;
use std::default::Default; use std::default::Default;
use mangui::{SharedNode, nodes::Style, taffy::prelude::Size, femtovg::{Paint, Color}}; 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};
make_component!( make_component!(
ComponentDemo, ComponentDemo,
Logic { Logic {
let test = false; let radius = 5.;
} }
Component { Component {
@Rectangle { @layout {
// style: Style { @Rectangle {
// layout: TaffyStyle { radius,
// min_size: Size { ..Default::default()
// width: Dimension::Points(50.), }
// height: Dimension::Points(100.) ..Default::default()
// },
// ..Default::default()
// },
// ..Default::default()
// },
// fill: Paint::color(Color::rgb(0, 0, 255)),
// radius: 5.,
// ..Default::default()
} }
} }
); );

View file

@ -1,20 +1,29 @@
use proc_macro::{TokenStream, TokenTree, Ident, Group, Punct, Span}; use proc_macro::{TokenStream, TokenTree, Ident, Group, Punct, Span};
use quote::quote; use quote::quote;
#[derive(Debug)]
struct Attribute { struct Attribute {
name: Ident, name: Ident,
default: Option<TokenStream>, default: Option<TokenStream>,
type_: TokenStream type_: TokenStream
} }
#[derive(Debug)]
enum ComponentType {
RealComponent,
Node
}
#[derive(Debug)] #[derive(Debug)]
struct ComponentUsed { struct ComponentUsed {
name: Ident, name: Ident,
contents: TokenStream, contents: TokenStream,
parent: Option<usize> parent: Option<usize>,
component_type: ComponentType
} }
#[proc_macro] #[proc_macro]
/// If you have syntax errors because of attributes, wrap the default value in parentheses.
pub fn make_component(item: TokenStream) -> TokenStream { pub fn make_component(item: TokenStream) -> TokenStream {
dbg!(&item); dbg!(&item);
@ -26,7 +35,7 @@ pub fn make_component(item: TokenStream) -> TokenStream {
dbg!(&name); dbg!(&name);
// let mut attributes: Vec<Attribute> = Vec::new(); let mut attributes: Vec<Attribute> = Vec::new();
// let mut struct_values = Vec::new(); // let mut struct_values = Vec::new();
@ -42,18 +51,110 @@ pub fn make_component(item: TokenStream) -> TokenStream {
last_identifier = Some(ident.to_string()); last_identifier = Some(ident.to_string());
let ident = ident.to_string(); let ident = ident.to_string();
if ident == "Logic" { match ident.as_str() {
// dbg!("Logic"); "Logic" | "Component" | "Attributes" => {},
} else if ident == "Component" { _ => panic!("Unknown identifier: {:?}", ident)
// dbg!("Component");
} else {
panic!("Unknown identifier: {:?}", ident);
} }
}, },
TokenTree::Group(group) => { TokenTree::Group(group) => {
match &last_identifier { match &last_identifier {
Some(ident) => { Some(ident) => {
match ident.as_str() { match ident.as_str() {
"Attributes" => {
// A struct-like definition of attributes
// Example syntax:
// Attributes { // we're here
// radius: f32 = 5.,
// fill: Paint,
// something: Something<(dyn Test)>
// }
// we need to match <> together, other groupings are already done by rust
let mut stream = group.stream().into_iter();
while let Some(token) = stream.next() {
let name = match token {
TokenTree::Ident(ident) => ident,
_ => panic!("Expected ident")
};
let colon = stream.next().unwrap();
let colon = match colon {
TokenTree::Punct(punct) => {
if punct.as_char() != ':' {
panic!("Expected :");
}
punct
},
_ => panic!("Expected :")
};
let mut type_ = TokenStream::new();
let mut last_was_set = false;
let mut ltgt_count = 0;
while let Some(token) = stream.next() {
match token {
TokenTree::Ident(ident) => {
type_.extend(Some(TokenTree::Ident(ident)));
},
TokenTree::Punct(punct) => {
if ltgt_count == 0 && punct.as_char() == ',' {
break;
} else if ltgt_count == 0 && punct.as_char() == '=' {
last_was_set = true;
break;
} else {
if punct.as_char() == '<' {
ltgt_count += 1;
} else if punct.as_char() == '>' {
ltgt_count -= 1;
}
type_.extend(Some(TokenTree::Punct(punct)));
}
},
_ => {
type_.extend(Some(token));
}
}
}
if last_was_set {
let mut default = TokenStream::new();
while let Some(token) = stream.next() {
match token {
TokenTree::Ident(ident) => {
default.extend(Some(TokenTree::Ident(ident)));
},
TokenTree::Punct(punct) => {
if punct.as_char() == ',' {
break;
} else {
default.extend(Some(TokenTree::Punct(punct)));
}
},
_ => {
default.extend(Some(token));
}
}
}
attributes.push(Attribute {
name,
default: Some(default),
type_
});
} else {
attributes.push(Attribute {
name,
default: None,
type_
});
}
}
},
"Logic" => { "Logic" => {
main_logic.push(group.stream()); main_logic.push(group.stream());
}, },
@ -131,7 +232,16 @@ pub fn make_component(item: TokenStream) -> TokenStream {
let ident = Ident::new(&format!("comp{}", i), Span::call_site()); let ident = Ident::new(&format!("comp{}", i), Span::call_site());
let midstream = TokenStream::from(quote!(: rusalka::SharedComponent<)); let mut midstream = TokenStream::from(quote!(: rusalka::));
match component.component_type {
ComponentType::RealComponent => {
midstream.extend(TokenStream::from(quote!(SharedComponent<)));
},
ComponentType::Node => {
midstream.extend(TokenStream::from(quote!(SharedNodeComponent<)));
}
}
let component_name = component.name.clone(); let component_name = component.name.clone();
@ -153,14 +263,44 @@ pub fn make_component(item: TokenStream) -> TokenStream {
let component_struct_group = Group::new(proc_macro::Delimiter::Brace, component_struct_stream); let component_struct_group = Group::new(proc_macro::Delimiter::Brace, component_struct_stream);
output.extend(Some(TokenTree::Group(component_struct_group))); output.extend(Some(TokenTree::Group(component_struct_group)));
let attributes_struct_stream = TokenStream::new();
// attributes TBD // attributes TBD
output.extend(TokenStream::from(quote!(pub struct))); let attributes_struct_stream = TokenStream::new();
output.extend(TokenStream::from(quote!(#[derive(Default)] pub struct)));
output.extend(Some(TokenTree::Ident(attributes_ident.clone()))); output.extend(Some(TokenTree::Ident(attributes_ident.clone())));
output.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Brace, attributes_struct_stream)))); output.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Brace, attributes_struct_stream))));
// partial attributes
let partial_attributes_ident = Ident::new(&format!("Partial{str_name}Attributes"), Span::call_site());
output.extend(TokenStream::from(quote!(#[derive(Default)] pub struct)));
output.extend(Some(TokenTree::Ident(partial_attributes_ident.clone())));
output.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Brace, TokenStream::new()))));
// impl From<Attributes> for PartialAttributes
output.extend(TokenStream::from(quote!(impl From<)));
output.extend(Some(TokenTree::Ident(attributes_ident.clone())));
output.extend(TokenStream::from(quote!(> for)));
output.extend(Some(TokenTree::Ident(partial_attributes_ident.clone())));
let mut from_stream = TokenStream::new();
from_stream.extend(TokenStream::from(quote!(fn from)));
let mut from_args = TokenStream::new();
from_args.extend(TokenStream::from(quote!(attrs:)));
from_args.extend(Some(TokenTree::Ident(attributes_ident.clone())));
from_stream.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Parenthesis, from_args))));
from_stream.extend(TokenStream::from(quote!(-> Self)));
let mut from_fn_stream = TokenStream::new();
from_fn_stream.extend(TokenStream::from(quote!(Self {})));
from_stream.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Brace, from_fn_stream))));
output.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Brace, from_stream))));
// Component impl // Component impl
output.extend(TokenStream::from(quote!(impl rusalka::component::Component for))); output.extend(TokenStream::from(quote!(impl rusalka::component::Component for)));
@ -171,6 +311,9 @@ pub fn make_component(item: TokenStream) -> TokenStream {
component_impl_stream.extend(TokenStream::from(quote!(type ComponentAttrs =))); component_impl_stream.extend(TokenStream::from(quote!(type ComponentAttrs =)));
component_impl_stream.extend(Some(TokenTree::Ident(attributes_ident.clone()))); component_impl_stream.extend(Some(TokenTree::Ident(attributes_ident.clone())));
component_impl_stream.extend(TokenStream::from(quote!(;))); component_impl_stream.extend(TokenStream::from(quote!(;)));
component_impl_stream.extend(TokenStream::from(quote!(type PartialComponentAttrs =)));
component_impl_stream.extend(Some(TokenTree::Ident(partial_attributes_ident.clone())));
component_impl_stream.extend(TokenStream::from(quote!(;)));
// fn new // fn new
@ -196,25 +339,36 @@ pub fn make_component(item: TokenStream) -> TokenStream {
let mut component_stream = TokenStream::new(); let mut component_stream = TokenStream::new();
component_stream.extend(Some(TokenTree::Ident(component_name.clone()))); component_stream.extend(Some(TokenTree::Ident(component_name.clone())));
component_stream.extend(TokenStream::from(quote!(::new)));
let mut component_new_stream = TokenStream::new(); match component.component_type {
ComponentType::RealComponent => {
component_stream.extend(TokenStream::from(quote!(::new)));
let component_attributes = Ident::new(&format!("{}Attributes", component_name.to_string()), Span::call_site()); let mut component_new_stream = TokenStream::new();
component_new_stream.extend(Some(TokenTree::Ident(component_attributes))); // The following would allow not importing ComponentAttributes, but rust doesn't support it outside of nightly just yet
// component_new_stream.extend(Some(TokenTree::Punct(Punct::new('<', proc_macro::Spacing::Alone))));
let component_attributes_group_stream = TokenStream::new(); // component_new_stream.extend(Some(TokenTree::Ident(component_name.clone())));
// component_new_stream.extend(TokenStream::from(quote!(as Component>::ComponentAttrs)));
let components_attributes_group = Group::new(proc_macro::Delimiter::Brace, component_attributes_group_stream);
component_new_stream.extend(Some(TokenTree::Ident(Ident::new(&format!("{}Attributes", component_name), Span::call_site()))));
component_new_stream.extend(Some(TokenTree::Group(components_attributes_group)));
let components_attributes_group = Group::new(proc_macro::Delimiter::Brace, component.contents.clone());
let component_new_group = Group::new(proc_macro::Delimiter::Parenthesis, component_new_stream);
component_new_stream.extend(Some(TokenTree::Group(components_attributes_group)));
component_stream.extend(Some(TokenTree::Group(component_new_group)));
let component_new_group = Group::new(proc_macro::Delimiter::Parenthesis, component_new_stream);
new_returnvalue_stream.extend(wrap_in_arcmutex(component_stream));
component_stream.extend(Some(TokenTree::Group(component_new_group)));
new_returnvalue_stream.extend(wrap_in_arcmutex(component_stream));
},
ComponentType::Node => {
let node_group = Group::new(proc_macro::Delimiter::Brace, component.contents.clone());
component_stream.extend(Some(TokenTree::Group(node_group)));
new_returnvalue_stream.extend(wrap_in_arcrwlock(component_stream));
}
}
new_returnvalue_stream.extend(TokenStream::from(quote!(,))); new_returnvalue_stream.extend(TokenStream::from(quote!(,)));
i+=1; i+=1;
@ -230,7 +384,10 @@ pub fn make_component(item: TokenStream) -> TokenStream {
// fn set // fn set
component_impl_stream.extend(TokenStream::from(quote!(fn set(&mut self, attrs: Self::ComponentAttrs) { self.attrs = attrs; }))); component_impl_stream.extend(TokenStream::from(quote!(fn set(&mut self, attrs: Self::PartialComponentAttrs))));
let set_stream = TokenStream::new();
component_impl_stream.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Brace, set_stream))));
// fn get // fn get
@ -244,25 +401,75 @@ pub fn make_component(item: TokenStream) -> TokenStream {
for i in 0..components_used.len() { for i in 0..components_used.len() {
let ident = Ident::new(&format!("comp{}", i), Span::call_site()); let ident = Ident::new(&format!("comp{}", i), Span::call_site());
let component = &components_used.get(i).unwrap();
let mut component_stream = TokenStream::new(); match component.component_type {
ComponentType::RealComponent => {
let mut component_stream = TokenStream::new();
component_stream.extend(TokenStream::from(quote!(self.)));
component_stream.extend(Some(TokenTree::Ident(ident)));
component_stream.extend(TokenStream::from(quote!(.lock().unwrap().mount)));
let mut component_mount_stream = TokenStream::new();
component_stream.extend(TokenStream::from(quote!(self.))); match component.parent {
component_stream.extend(Some(TokenTree::Ident(ident))); Some(parent) => {
component_stream.extend(TokenStream::from(quote!(.lock().unwrap().mount))); let parent_ident = Ident::new(&format!("comp{}", parent), Span::call_site());
let mut component_mount_stream = TokenStream::new(); let mut node_insert_self_stream = TokenStream::new();
component_mount_stream.extend(TokenStream::from(quote!(parent))); node_insert_self_stream.extend(TokenStream::from(quote!(self.)));
component_mount_stream.extend(TokenStream::from(quote!(,))); node_insert_self_stream.extend(Some(TokenTree::Ident(parent_ident)));
component_mount_stream.extend(TokenStream::from(quote!(before))); node_insert_self_stream.extend(TokenStream::from(quote!(.clone())));
let component_mount_group = Group::new(proc_macro::Delimiter::Parenthesis, component_mount_stream); let node_insert_self_group = Group::new(proc_macro::Delimiter::Brace, node_insert_self_stream);
component_mount_stream.extend(TokenStream::from(quote!(&)));
component_mount_stream.extend(Some(TokenTree::Group(node_insert_self_group)));
},
None => {
component_mount_stream.extend(TokenStream::from(quote!(parent)));
}
}
component_mount_stream.extend(TokenStream::from(quote!(,)));
component_mount_stream.extend(TokenStream::from(quote!(before)));
let component_mount_group = Group::new(proc_macro::Delimiter::Parenthesis, component_mount_stream);
component_stream.extend(Some(TokenTree::Group(component_mount_group)));
mount_stream.extend(component_stream);
mount_stream.extend(TokenStream::from(quote!(;)));
},
ComponentType::Node => {
let mut node_stream = TokenStream::new();
component_stream.extend(Some(TokenTree::Group(component_mount_group))); node_stream.extend(TokenStream::from(quote!(rusalka::nodes::insert)));
let mut node_insert_stream = TokenStream::new();
node_insert_stream.extend(TokenStream::from(quote!(parent,)));
node_insert_stream.extend(TokenStream::from(quote!(&)));
let mut node_insert_self_stream = TokenStream::new();
node_insert_self_stream.extend(TokenStream::from(quote!(self.)));
node_insert_self_stream.extend(Some(TokenTree::Ident(ident)));
node_insert_self_stream.extend(TokenStream::from(quote!(.clone())));
let node_insert_self_group = Group::new(proc_macro::Delimiter::Brace, node_insert_self_stream);
node_insert_stream.extend(Some(TokenTree::Group(node_insert_self_group)));
node_insert_stream.extend(TokenStream::from(quote!(,)));
node_insert_stream.extend(TokenStream::from(quote!(before)));
node_stream.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Parenthesis, node_insert_stream))));
mount_stream.extend(node_stream);
mount_stream.extend(TokenStream::from(quote!(;)));
}
}
mount_stream.extend(component_stream);
mount_stream.extend(TokenStream::from(quote!(;)));
} }
let mount_group = Group::new(proc_macro::Delimiter::Brace, mount_stream); let mount_group = Group::new(proc_macro::Delimiter::Brace, mount_stream);
@ -276,15 +483,39 @@ pub fn make_component(item: TokenStream) -> TokenStream {
for i in 0..components_used.len() { for i in 0..components_used.len() {
let ident = Ident::new(&format!("comp{}", i), Span::call_site()); let ident = Ident::new(&format!("comp{}", i), Span::call_site());
let component = &components_used.get(i).unwrap();
let mut component_stream = TokenStream::new(); match component.component_type {
ComponentType::RealComponent => {
let mut component_stream = TokenStream::new();
component_stream.extend(TokenStream::from(quote!(self.)));
component_stream.extend(Some(TokenTree::Ident(ident)));
component_stream.extend(TokenStream::from(quote!(.lock().unwrap().unmount())));
unmount_stream.extend(component_stream);
unmount_stream.extend(TokenStream::from(quote!(;)));
},
ComponentType::Node => {
unmount_stream.extend(TokenStream::from(quote!(rusalka::nodes::detach)));
component_stream.extend(TokenStream::from(quote!(self.))); let mut node_detach_stream = TokenStream::new();
component_stream.extend(Some(TokenTree::Ident(ident))); node_detach_stream.extend(TokenStream::from(quote!(&)));
component_stream.extend(TokenStream::from(quote!(.lock().unwrap().unmount())));
unmount_stream.extend(component_stream); let mut node_detach_self_stream = TokenStream::new();
unmount_stream.extend(TokenStream::from(quote!(;)));
node_detach_self_stream.extend(TokenStream::from(quote!(self.)));
node_detach_self_stream.extend(Some(TokenTree::Ident(ident)));
node_detach_self_stream.extend(TokenStream::from(quote!(.clone())));
let node_detach_self_group = Group::new(proc_macro::Delimiter::Brace, node_detach_self_stream);
node_detach_stream.extend(Some(TokenTree::Group(node_detach_self_group)));
let node_detach_group = Group::new(proc_macro::Delimiter::Parenthesis, node_detach_stream);
unmount_stream.extend(Some(TokenTree::Group(node_detach_group)));
unmount_stream.extend(TokenStream::from(quote!(;)));
}
}
} }
let unmount_group = Group::new(proc_macro::Delimiter::Brace, unmount_stream); let unmount_group = Group::new(proc_macro::Delimiter::Brace, unmount_stream);
@ -292,11 +523,13 @@ pub fn make_component(item: TokenStream) -> TokenStream {
// fn update // fn update
component_impl_stream.extend(TokenStream::from(quote!(fn update(&self) {}))); component_impl_stream.extend(TokenStream::from(quote!(fn update(&self, bitmap: &[u32]) { self.check_update(bitmap); })));
output.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Brace, component_impl_stream)))); output.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Brace, component_impl_stream))));
dbg!(&output); // dbg!(&output);
dbg!(attributes);
println!("{}", output.to_string()); println!("{}", output.to_string());
@ -325,6 +558,26 @@ fn wrap_in_arcmutex(stream: TokenStream) -> TokenStream {
output output
} }
fn wrap_in_arcrwlock(stream: TokenStream) -> TokenStream {
let mut output = TokenStream::new();
output.extend(TokenStream::from(quote!(std::sync::Arc::new)));
let mut mutex_group = Group::new(proc_macro::Delimiter::Parenthesis, stream);
let mut mutex_stream = TokenStream::new();
mutex_stream.extend(TokenStream::from(quote!(std::sync::RwLock::new)));
mutex_stream.extend(Some(TokenTree::Group(mutex_group)));
let arc_group = Group::new(proc_macro::Delimiter::Parenthesis, mutex_stream);
output.extend(Some(TokenTree::Group(arc_group)));
output
}
/// Call this after @ /// Call this after @
/// Will return the main component as well as any sub-components /// Will return the main component as well as any sub-components
/// name: the name of the component /// name: the name of the component
@ -339,10 +592,18 @@ fn parse_components(name: Ident, group: Group, next: usize, parent: Option<usize
// dbg!(&name); // dbg!(&name);
let name_starts_lowercase = name.to_string().chars().next().unwrap().is_lowercase();
let this_component = ComponentUsed { let this_component = ComponentUsed {
name, name: if name_starts_lowercase {
let mut str = name.to_string();
str.replace_range(0..1, &str[0..1].to_uppercase());
let span = name.span();
Ident::new(&str, span)
} else { name },
contents: self_stream.clone(), contents: self_stream.clone(),
parent parent,
component_type: if name_starts_lowercase { ComponentType::Node } else { ComponentType::RealComponent }
}; };
@ -367,6 +628,7 @@ fn parse_components(name: Ident, group: Group, next: usize, parent: Option<usize
let components = parse_components(ident, group, next + components_found.len() + 1, Some(next)); let components = parse_components(ident, group, next + components_found.len() + 1, Some(next));
components_found.extend(components); components_found.extend(components);
} else { } else {
self_stream.extend(Some(TokenTree::Punct(punct)));
while let Some(token) = group.next() { while let Some(token) = group.next() {
match token { match token {
TokenTree::Punct(punct) => { TokenTree::Punct(punct) => {
@ -383,16 +645,16 @@ fn parse_components(name: Ident, group: Group, next: usize, parent: Option<usize
} }
} }
}, },
_ => { any => {
// skip until next ',', writing to self_stream // skip until next ',', writing to self_stream
self_stream.extend(Some(any));
while let Some(token) = group.next() { while let Some(token) = group.next() {
match token { match token {
TokenTree::Punct(punct) => { TokenTree::Punct(punct) => {
if punct.as_char() == ',' { let char = punct.as_char();
self_stream.extend(Some(TokenTree::Punct(punct)));
if char == ',' {
break; break;
} else {
self_stream.extend(Some(TokenTree::Punct(punct)));
} }
}, },
_ => { _ => {

View file

@ -1,12 +1,20 @@
use mangui::SharedNode; use mangui::{SharedNode, nodes::Node};
/// A rusalka component /// A rusalka component
pub trait Component { pub trait Component {
type ComponentAttrs; type ComponentAttrs: Default;
type PartialComponentAttrs: Default + From<Self::ComponentAttrs>;
const UPDATE_LENGTH : usize = 0;
fn new(attr: Self::ComponentAttrs) -> Self; fn new(attr: Self::ComponentAttrs) -> Self;
fn get(&self) -> &Self::ComponentAttrs; fn get(&self) -> &Self::ComponentAttrs;
fn set(&mut self, attr: Self::ComponentAttrs); fn set(&mut self, attr: Self::PartialComponentAttrs);
fn mount(&self, parent: &SharedNode, before: Option<&SharedNode>); fn mount(&self, parent: &SharedNode, before: Option<&SharedNode>);
fn update(&self); fn update(&self, bitmap: &[u32]);
fn unmount(&self); fn unmount(&self);
}
fn check_update(&self, bitmap: &[u32]) -> () {
if bitmap.len() != Self::UPDATE_LENGTH {
panic!("Bitmap length does not match update length");
}
}
}

View file

@ -1,8 +1,10 @@
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex, RwLock};
use component::Component; use component::Component;
use mangui::nodes::Node;
pub mod component; pub mod component;
pub mod nodes; pub mod nodes;
pub type SharedComponent<T: Component> = Arc<Mutex<T>>; pub type SharedComponent<T: Component> = Arc<Mutex<T>>;
pub type SharedNodeComponent<T: Node> = Arc<RwLock<T>>;

View file

@ -3,7 +3,6 @@ use mangui::SharedNode;
pub mod primitives; pub mod primitives;
pub fn detach(node: &SharedNode) { pub fn detach(node: &SharedNode) {
if let Some(parent) = node.read().unwrap().parent() { if let Some(parent) = node.read().unwrap().parent() {
parent.write().unwrap().remove_child(node).unwrap(); parent.write().unwrap().remove_child(node).unwrap();

View file

@ -9,15 +9,33 @@ use crate::component::Component;
use super::{insert, detach}; use super::{insert, detach};
pub struct Rectangle { pub struct Rectangle {
node: SharedNode, node: Arc<RwLock<primitives::Rectangle>>,
attrs: RectangleAttributes attrs: RectangleAttributes
} }
#[derive(Default)] #[derive(Default)]
pub struct RectangleAttributes {} pub struct RectangleAttributes {
pub radius: f32
}
#[derive(Default)]
pub struct PartialRectangleAttributes {
pub radius: Option<f32>
}
impl From<RectangleAttributes> for PartialRectangleAttributes {
fn from(attrs: RectangleAttributes) ->
Self {
Self {
radius: Some(attrs.radius)
}
}
}
impl Component for Rectangle { impl Component for Rectangle {
type ComponentAttrs = RectangleAttributes; type ComponentAttrs = RectangleAttributes;
type PartialComponentAttrs = PartialRectangleAttributes;
const UPDATE_LENGTH : usize = 1;
fn new(attrs: Self::ComponentAttrs) -> Self { fn new(attrs: Self::ComponentAttrs) -> Self {
Self { Self {
node: Arc::new(RwLock::new(primitives::Rectangle { node: Arc::new(RwLock::new(primitives::Rectangle {
@ -32,22 +50,38 @@ impl Component for Rectangle {
..Default::default() ..Default::default()
}, },
fill: Paint::color(Color::rgb(0, 0, 255)), fill: Paint::color(Color::rgb(0, 0, 255)),
radius: 5., radius: attrs.radius,
..Default::default() ..Default::default()
})), })),
attrs attrs
} }
} }
fn set(&mut self, attrs: Self::ComponentAttrs) { self.attrs = attrs; } fn set(&mut self, attrs: Self::PartialComponentAttrs) {
let mut to_update = [0];
if let Some(radius) = attrs.radius {
self.attrs.radius = radius;
to_update[0] |= 1;
}
if to_update[0] != 0 {
self.update(&to_update);
}
}
fn get(&self) -> &Self::ComponentAttrs { &self.attrs } fn get(&self) -> &Self::ComponentAttrs { &self.attrs }
fn mount(&self, parent: &SharedNode, before: Option<&SharedNode>) { fn mount(&self, parent: &SharedNode, before: Option<&SharedNode>) {
insert(parent, &self.node, before); insert(parent, &{self.node.clone()}, before);
} }
fn update(&self) {} fn update(&self, bitmap: &[u32]) {
self.check_update(bitmap);
if bitmap[0] & 1 != 0 {
self.node.write().unwrap().radius = self.attrs.radius;
}
}
fn unmount(&self) { fn unmount(&self) {
detach(&self.node); detach(&{self.node.clone()});
} }
} }