diff --git a/mangades/src/component_demo.rs b/mangades/src/component_demo.rs index a69d0c6..2ab9645 100644 --- a/mangades/src/component_demo.rs +++ b/mangades/src/component_demo.rs @@ -1,32 +1,59 @@ -use std::sync::{Arc, Mutex}; -use mangui::SharedNode; -use rusalka::{component::Component, nodes::primitives::{Rectangle, RectangleAttributes}, SharedComponent}; +use std::sync::{Arc, Mutex, RwLock}; +use mangui::{SharedNode, nodes::{layout::Layout, Style}, taffy::prelude::Size}; +use rusalka::{component::Component, nodes::{primitives::{Rectangle, RectangleAttributes}, insert, detach}, SharedComponent}; pub struct DemoComponent { rect: SharedComponent, attrs: DemoComponentAttributes, + layout: Arc> } +#[derive(Default)] pub struct DemoComponentAttributes {} +#[derive(Default)] +pub struct PartialDemoComponentAttributes {} + +impl From for PartialDemoComponentAttributes { + fn from(_attrs: DemoComponentAttributes) -> Self { + Self {} + } +} + impl Component for DemoComponent { type ComponentAttrs = DemoComponentAttributes; + type PartialComponentAttrs = PartialDemoComponentAttributes; fn new(attrs: Self::ComponentAttrs) -> 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, } } - 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 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) { self.rect.lock().unwrap().unmount(); + detach(&{self.layout.clone()}); } - fn update(&self) {} + fn update(&self, _bitmap: &[u32]) {} } diff --git a/mangades/src/component_demo_syntax.rs b/mangades/src/component_demo_syntax.rs index e6f2ef9..3e6e9e5 100644 --- a/mangades/src/component_demo_syntax.rs +++ b/mangades/src/component_demo_syntax.rs @@ -1,29 +1,21 @@ use rusalka_macro::make_component; 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}; make_component!( ComponentDemo, Logic { - let test = false; + let radius = 5.; } Component { - @Rectangle { - // style: Style { - // layout: TaffyStyle { - // min_size: Size { - // width: Dimension::Points(50.), - // height: Dimension::Points(100.) - // }, - // ..Default::default() - // }, - // ..Default::default() - // }, - // fill: Paint::color(Color::rgb(0, 0, 255)), - // radius: 5., - // ..Default::default() + @layout { + @Rectangle { + radius, + ..Default::default() + } + ..Default::default() } } ); diff --git a/rusalka-macro/src/lib.rs b/rusalka-macro/src/lib.rs index b590f65..4a00bb1 100644 --- a/rusalka-macro/src/lib.rs +++ b/rusalka-macro/src/lib.rs @@ -1,20 +1,29 @@ use proc_macro::{TokenStream, TokenTree, Ident, Group, Punct, Span}; use quote::quote; +#[derive(Debug)] struct Attribute { name: Ident, default: Option, type_: TokenStream } +#[derive(Debug)] +enum ComponentType { + RealComponent, + Node +} + #[derive(Debug)] struct ComponentUsed { name: Ident, contents: TokenStream, - parent: Option + parent: Option, + component_type: ComponentType } #[proc_macro] +/// If you have syntax errors because of attributes, wrap the default value in parentheses. pub fn make_component(item: TokenStream) -> TokenStream { dbg!(&item); @@ -26,7 +35,7 @@ pub fn make_component(item: TokenStream) -> TokenStream { dbg!(&name); - // let mut attributes: Vec = Vec::new(); + let mut attributes: Vec = 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()); let ident = ident.to_string(); - if ident == "Logic" { - // dbg!("Logic"); - } else if ident == "Component" { - // dbg!("Component"); - } else { - panic!("Unknown identifier: {:?}", ident); + match ident.as_str() { + "Logic" | "Component" | "Attributes" => {}, + _ => panic!("Unknown identifier: {:?}", ident) } }, TokenTree::Group(group) => { match &last_identifier { Some(ident) => { 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" => { 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 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(); @@ -153,14 +263,44 @@ pub fn make_component(item: TokenStream) -> TokenStream { let component_struct_group = Group::new(proc_macro::Delimiter::Brace, component_struct_stream); output.extend(Some(TokenTree::Group(component_struct_group))); - let attributes_struct_stream = TokenStream::new(); // 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::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 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 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(Some(TokenTree::Ident(attributes_ident.clone()))); 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 @@ -196,25 +339,36 @@ pub fn make_component(item: TokenStream) -> TokenStream { let mut component_stream = TokenStream::new(); 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()); - - component_new_stream.extend(Some(TokenTree::Ident(component_attributes))); - - let component_attributes_group_stream = TokenStream::new(); - - let components_attributes_group = Group::new(proc_macro::Delimiter::Brace, component_attributes_group_stream); - - component_new_stream.extend(Some(TokenTree::Group(components_attributes_group))); - - let component_new_group = Group::new(proc_macro::Delimiter::Parenthesis, component_new_stream); - - component_stream.extend(Some(TokenTree::Group(component_new_group))); - - new_returnvalue_stream.extend(wrap_in_arcmutex(component_stream)); + let mut component_new_stream = TokenStream::new(); + + // 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)))); + // component_new_stream.extend(Some(TokenTree::Ident(component_name.clone()))); + // component_new_stream.extend(TokenStream::from(quote!(as Component>::ComponentAttrs))); + + component_new_stream.extend(Some(TokenTree::Ident(Ident::new(&format!("{}Attributes", component_name), Span::call_site())))); + + let components_attributes_group = Group::new(proc_macro::Delimiter::Brace, component.contents.clone()); + + component_new_stream.extend(Some(TokenTree::Group(components_attributes_group))); + + let component_new_group = Group::new(proc_macro::Delimiter::Parenthesis, component_new_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!(,))); i+=1; @@ -230,7 +384,10 @@ pub fn make_component(item: TokenStream) -> TokenStream { // 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 @@ -244,25 +401,75 @@ pub fn make_component(item: TokenStream) -> TokenStream { for i in 0..components_used.len() { 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.))); - component_stream.extend(Some(TokenTree::Ident(ident))); - component_stream.extend(TokenStream::from(quote!(.lock().unwrap().mount))); + match component.parent { + Some(parent) => { + 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))); - component_mount_stream.extend(TokenStream::from(quote!(,))); - component_mount_stream.extend(TokenStream::from(quote!(before))); + node_insert_self_stream.extend(TokenStream::from(quote!(self.))); + node_insert_self_stream.extend(Some(TokenTree::Ident(parent_ident))); + 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); @@ -276,15 +483,39 @@ pub fn make_component(item: TokenStream) -> TokenStream { for i in 0..components_used.len() { 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.))); - component_stream.extend(Some(TokenTree::Ident(ident))); - component_stream.extend(TokenStream::from(quote!(.lock().unwrap().unmount()))); + let mut node_detach_stream = TokenStream::new(); + node_detach_stream.extend(TokenStream::from(quote!(&))); - unmount_stream.extend(component_stream); - unmount_stream.extend(TokenStream::from(quote!(;))); + let mut node_detach_self_stream = TokenStream::new(); + + 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); @@ -292,11 +523,13 @@ pub fn make_component(item: TokenStream) -> TokenStream { // 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)))); - dbg!(&output); + // dbg!(&output); + + dbg!(attributes); println!("{}", output.to_string()); @@ -325,6 +558,26 @@ fn wrap_in_arcmutex(stream: TokenStream) -> TokenStream { 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 @ /// Will return the main component as well as any sub-components /// name: the name of the component @@ -339,10 +592,18 @@ fn parse_components(name: Ident, group: Group, next: usize, parent: Option { @@ -383,16 +645,16 @@ fn parse_components(name: Ident, group: Group, next: usize, parent: Option { + any => { // skip until next ',', writing to self_stream - + self_stream.extend(Some(any)); while let Some(token) = group.next() { match token { TokenTree::Punct(punct) => { - if punct.as_char() == ',' { + let char = punct.as_char(); + self_stream.extend(Some(TokenTree::Punct(punct))); + if char == ',' { break; - } else { - self_stream.extend(Some(TokenTree::Punct(punct))); } }, _ => { diff --git a/rusalka/src/component.rs b/rusalka/src/component.rs index fd1d9ed..f1b0bf3 100644 --- a/rusalka/src/component.rs +++ b/rusalka/src/component.rs @@ -1,12 +1,20 @@ -use mangui::SharedNode; +use mangui::{SharedNode, nodes::Node}; /// A rusalka component pub trait Component { - type ComponentAttrs; + type ComponentAttrs: Default; + type PartialComponentAttrs: Default + From; + const UPDATE_LENGTH : usize = 0; fn new(attr: Self::ComponentAttrs) -> Self; 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 update(&self); + fn update(&self, bitmap: &[u32]); fn unmount(&self); -} \ No newline at end of file + + fn check_update(&self, bitmap: &[u32]) -> () { + if bitmap.len() != Self::UPDATE_LENGTH { + panic!("Bitmap length does not match update length"); + } + } +} diff --git a/rusalka/src/lib.rs b/rusalka/src/lib.rs index 2cd0b3d..63cf858 100644 --- a/rusalka/src/lib.rs +++ b/rusalka/src/lib.rs @@ -1,8 +1,10 @@ -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, Mutex, RwLock}; use component::Component; +use mangui::nodes::Node; pub mod component; pub mod nodes; -pub type SharedComponent = Arc>; \ No newline at end of file +pub type SharedComponent = Arc>; +pub type SharedNodeComponent = Arc>; \ No newline at end of file diff --git a/rusalka/src/nodes/mod.rs b/rusalka/src/nodes/mod.rs index c25d171..009eabc 100644 --- a/rusalka/src/nodes/mod.rs +++ b/rusalka/src/nodes/mod.rs @@ -3,7 +3,6 @@ use mangui::SharedNode; pub mod primitives; - pub fn detach(node: &SharedNode) { if let Some(parent) = node.read().unwrap().parent() { parent.write().unwrap().remove_child(node).unwrap(); diff --git a/rusalka/src/nodes/primitives.rs b/rusalka/src/nodes/primitives.rs index 1dfd222..87d4ced 100644 --- a/rusalka/src/nodes/primitives.rs +++ b/rusalka/src/nodes/primitives.rs @@ -9,15 +9,33 @@ use crate::component::Component; use super::{insert, detach}; pub struct Rectangle { - node: SharedNode, + node: Arc>, attrs: RectangleAttributes } #[derive(Default)] -pub struct RectangleAttributes {} +pub struct RectangleAttributes { + pub radius: f32 +} + +#[derive(Default)] +pub struct PartialRectangleAttributes { + pub radius: Option +} + +impl From for PartialRectangleAttributes { + fn from(attrs: RectangleAttributes) -> + Self { + Self { + radius: Some(attrs.radius) + } + } +} impl Component for Rectangle { type ComponentAttrs = RectangleAttributes; + type PartialComponentAttrs = PartialRectangleAttributes; + const UPDATE_LENGTH : usize = 1; fn new(attrs: Self::ComponentAttrs) -> Self { Self { node: Arc::new(RwLock::new(primitives::Rectangle { @@ -32,22 +50,38 @@ impl Component for Rectangle { ..Default::default() }, fill: Paint::color(Color::rgb(0, 0, 255)), - radius: 5., + radius: attrs.radius, ..Default::default() })), 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 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) { - detach(&self.node); + detach(&{self.node.clone()}); } } \ No newline at end of file