mirror of
https://github.com/danbulant/mangui
synced 2026-07-08 20:30:35 +00:00
work in progress reactivity
This commit is contained in:
parent
c83bd506ab
commit
527af977e5
9 changed files with 240 additions and 78 deletions
|
|
@ -1,11 +1,13 @@
|
||||||
use std::sync::{Arc, Mutex, RwLock};
|
use std::sync::{Arc, Mutex, RwLock};
|
||||||
use mangui::{SharedNode, nodes::{layout::Layout, Style}, taffy::prelude::Size};
|
use mangui::{SharedNode, nodes::{layout::Layout, Style}, taffy::prelude::Size};
|
||||||
use rusalka::{component::Component, nodes::{primitives::{Rectangle, RectangleAttributes}, insert, detach}, SharedComponent};
|
use rusalka::{component::Component, nodes::{primitives::{Rectangle, RectangleAttributes}, insert, detach}, SharedComponent, WeakSharedComponent, invalidator::Invalidator};
|
||||||
|
|
||||||
pub struct DemoComponent {
|
pub struct DemoComponent {
|
||||||
rect: SharedComponent<Rectangle>,
|
rect: SharedComponent<Rectangle>,
|
||||||
attrs: DemoComponentAttributes,
|
attrs: DemoComponentAttributes,
|
||||||
layout: Arc<RwLock<Layout>>
|
layout: Arc<RwLock<Layout>>,
|
||||||
|
selfref: WeakSharedComponent<Self>,
|
||||||
|
test: Arc<Mutex<Invalidator<bool>>>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
@ -23,14 +25,15 @@ impl From<DemoComponentAttributes> for PartialDemoComponentAttributes {
|
||||||
impl Component for DemoComponent {
|
impl Component for DemoComponent {
|
||||||
type ComponentAttrs = DemoComponentAttributes;
|
type ComponentAttrs = DemoComponentAttributes;
|
||||||
type PartialComponentAttrs = PartialDemoComponentAttributes;
|
type PartialComponentAttrs = PartialDemoComponentAttributes;
|
||||||
fn new(attrs: Self::ComponentAttrs) -> Self {
|
fn new(attrs: Self::ComponentAttrs, selfref: WeakSharedComponent<Self>) -> Self {
|
||||||
Self {
|
let test = Arc::new(Mutex::new(Invalidator::new(false)));
|
||||||
rect: Arc::new(Mutex::new(Rectangle::new(RectangleAttributes { ..Default::default() }))),
|
let self_ = Self {
|
||||||
|
rect: Arc::new_cyclic(|selfref| Mutex::new(Rectangle::new(RectangleAttributes { ..Default::default() }, selfref.clone()))),
|
||||||
layout: Arc::new(RwLock::new(Layout {
|
layout: Arc::new(RwLock::new(Layout {
|
||||||
style: Style {
|
style: Style {
|
||||||
layout: mangui::nodes::TaffyStyle {
|
layout: mangui::nodes::TaffyStyle {
|
||||||
min_size: Size {
|
min_size: Size {
|
||||||
width: mangui::taffy::style::Dimension::Points(50.),
|
width: mangui::taffy::style::Dimension::Points( if **test.lock().unwrap() { 50. } else { 100. }),
|
||||||
height: mangui::taffy::style::Dimension::Points(100.)
|
height: mangui::taffy::style::Dimension::Points(100.)
|
||||||
},
|
},
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|
@ -40,7 +43,26 @@ impl Component for DemoComponent {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})),
|
})),
|
||||||
attrs,
|
attrs,
|
||||||
}
|
selfref,
|
||||||
|
test
|
||||||
|
};
|
||||||
|
let selfref = self_.selfref.clone();
|
||||||
|
self_.layout.write().unwrap().events.add_handler(Box::new(move |event| {
|
||||||
|
let selfref = selfref.upgrade().unwrap();
|
||||||
|
let self_ = selfref.lock().unwrap();
|
||||||
|
let test = &self_.test;
|
||||||
|
let attrs = &self_.attrs;
|
||||||
|
match event.event {
|
||||||
|
mangui::events::InnerEvent::MouseDown(_) => {
|
||||||
|
**test.lock().unwrap() = true;
|
||||||
|
},
|
||||||
|
mangui::events::InnerEvent::MouseUp(_) => {
|
||||||
|
**test.lock().unwrap() = false;
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
self_
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set(&mut self, _attrs: Self::PartialComponentAttrs) { }
|
fn set(&mut self, _attrs: Self::PartialComponentAttrs) { }
|
||||||
|
|
|
||||||
|
|
@ -6,18 +6,32 @@ use rusalka::nodes::primitives::{Rectangle, RectangleAttributes};
|
||||||
|
|
||||||
make_component!(
|
make_component!(
|
||||||
ComponentDemo,
|
ComponentDemo,
|
||||||
Logic {
|
MainLogic {
|
||||||
let radius = attrs.radius;
|
let radius = attrs.radius;
|
||||||
}
|
}
|
||||||
Attributes {
|
Attributes {
|
||||||
radius: f32
|
radius: f32
|
||||||
}
|
}
|
||||||
|
Variables {
|
||||||
|
test: bool = false
|
||||||
|
}
|
||||||
Component {
|
Component {
|
||||||
@layout {
|
@layout {
|
||||||
@Rectangle {
|
@Rectangle {
|
||||||
radius,
|
radius: if $test { radius } else { 0. },
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
|
$|event| {
|
||||||
|
match event.event {
|
||||||
|
mangui::events::InnerEvent::MouseDown(_) => {
|
||||||
|
$test = true;
|
||||||
|
},
|
||||||
|
mangui::events::InnerEvent::MouseUp(_) => {
|
||||||
|
$test = false;
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::sync::{RwLock, Arc, mpsc};
|
use std::sync::{RwLock, Arc, mpsc};
|
||||||
|
|
||||||
use mangui::{self, nodes::{layout::Layout, self, Style, TaffyStyle}, taffy::{self, prelude::Size, style::Dimension}, femtovg::{Paint, Color}, SharedNode, MainEntry};
|
use mangui::{self, nodes::{layout::Layout, self, Style, TaffyStyle}, taffy::{self, prelude::Size, style::Dimension}, femtovg::{Paint, Color}, SharedNode, MainEntry, events::NodeEvent};
|
||||||
|
|
||||||
mod component_demo;
|
mod component_demo;
|
||||||
mod component_demo_syntax;
|
mod component_demo_syntax;
|
||||||
|
|
@ -30,7 +30,8 @@ fn main() {
|
||||||
}));
|
}));
|
||||||
root.children.push(right_node.clone());
|
root.children.push(right_node.clone());
|
||||||
right_node.clone().write().unwrap().events.add_handler(Box::new(move |event| {
|
right_node.clone().write().unwrap().events.add_handler(Box::new(move |event| {
|
||||||
match event.event {
|
let NodeEvent { target, path, event } = event;
|
||||||
|
match event {
|
||||||
mangui::events::InnerEvent::MouseDown(_) => {
|
mangui::events::InnerEvent::MouseDown(_) => {
|
||||||
right_node.write().unwrap().fill = Paint::color(Color::rgb(255, 0, 255));
|
right_node.write().unwrap().fill = Paint::color(Color::rgb(255, 0, 255));
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,11 @@ struct Attribute {
|
||||||
type_: TokenStream
|
type_: TokenStream
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct EventListener {
|
||||||
|
callback: TokenStream
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum ComponentType {
|
enum ComponentType {
|
||||||
RealComponent,
|
RealComponent,
|
||||||
|
|
@ -19,7 +24,8 @@ struct ComponentUsed {
|
||||||
name: Ident,
|
name: Ident,
|
||||||
contents: TokenStream,
|
contents: TokenStream,
|
||||||
parent: Option<usize>,
|
parent: Option<usize>,
|
||||||
component_type: ComponentType
|
component_type: ComponentType,
|
||||||
|
event_listeners: Vec<EventListener>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro]
|
#[proc_macro]
|
||||||
|
|
@ -41,7 +47,7 @@ pub fn make_component(item: TokenStream) -> TokenStream {
|
||||||
|
|
||||||
let mut main_logic = Vec::new();
|
let mut main_logic = Vec::new();
|
||||||
|
|
||||||
// let mut reactive_variables = Vec::new();
|
let mut reactive_variables = Vec::new();
|
||||||
|
|
||||||
let mut components_used: Vec<ComponentUsed> = Vec::new();
|
let mut components_used: Vec<ComponentUsed> = Vec::new();
|
||||||
|
|
||||||
|
|
@ -52,7 +58,7 @@ pub fn make_component(item: TokenStream) -> TokenStream {
|
||||||
let ident = ident.to_string();
|
let ident = ident.to_string();
|
||||||
|
|
||||||
match ident.as_str() {
|
match ident.as_str() {
|
||||||
"Logic" | "Component" | "Attributes" => {},
|
"MainLogic" | "Component" | "Attributes" | "Variables" => {},
|
||||||
_ => panic!("Unknown identifier: {:?}", ident)
|
_ => panic!("Unknown identifier: {:?}", ident)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -60,7 +66,7 @@ pub fn make_component(item: TokenStream) -> TokenStream {
|
||||||
match &last_identifier {
|
match &last_identifier {
|
||||||
Some(ident) => {
|
Some(ident) => {
|
||||||
match ident.as_str() {
|
match ident.as_str() {
|
||||||
"Attributes" => {
|
"Attributes" | "Variables" => {
|
||||||
// A struct-like definition of attributes
|
// A struct-like definition of attributes
|
||||||
// Example syntax:
|
// Example syntax:
|
||||||
// Attributes { // we're here
|
// Attributes { // we're here
|
||||||
|
|
@ -120,6 +126,12 @@ pub fn make_component(item: TokenStream) -> TokenStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let array = if ident.as_str() == "Variables" {
|
||||||
|
&mut reactive_variables
|
||||||
|
} else {
|
||||||
|
&mut attributes
|
||||||
|
};
|
||||||
|
|
||||||
if last_was_set {
|
if last_was_set {
|
||||||
let mut default = TokenStream::new();
|
let mut default = TokenStream::new();
|
||||||
|
|
||||||
|
|
@ -141,13 +153,13 @@ pub fn make_component(item: TokenStream) -> TokenStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes.push(Attribute {
|
array.push(Attribute {
|
||||||
name,
|
name,
|
||||||
default: Some(default),
|
default: Some(default),
|
||||||
type_
|
type_
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
attributes.push(Attribute {
|
array.push(Attribute {
|
||||||
name,
|
name,
|
||||||
default: None,
|
default: None,
|
||||||
type_
|
type_
|
||||||
|
|
@ -155,7 +167,7 @@ pub fn make_component(item: TokenStream) -> TokenStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Logic" => {
|
"MainLogic" => {
|
||||||
main_logic.push(group.stream());
|
main_logic.push(group.stream());
|
||||||
},
|
},
|
||||||
"Component" => {
|
"Component" => {
|
||||||
|
|
@ -253,6 +265,19 @@ pub fn make_component(item: TokenStream) -> TokenStream {
|
||||||
i+=1;
|
i+=1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for variable in &reactive_variables {
|
||||||
|
component_struct_stream.extend(Some(TokenTree::Ident(variable.name.clone())));
|
||||||
|
component_struct_stream.extend(TokenStream::from(quote!(:)));
|
||||||
|
component_struct_stream.extend(TokenStream::from(quote!(Arc<Mutex<Invalidator<)));
|
||||||
|
component_struct_stream.extend(variable.type_.clone());
|
||||||
|
component_struct_stream.extend(TokenStream::from(quote!(>>>)));
|
||||||
|
component_struct_stream.extend(TokenStream::from(quote!(,)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// selfref
|
||||||
|
|
||||||
|
component_struct_stream.extend(TokenStream::from(quote!(selfref: rusalka::WeakSharedComponent<Self>,)));
|
||||||
|
|
||||||
// Attributes struct
|
// Attributes struct
|
||||||
|
|
||||||
let attributes_ident = Ident::new(&format!("{str_name}Attributes"), Span::call_site());
|
let attributes_ident = Ident::new(&format!("{str_name}Attributes"), Span::call_site());
|
||||||
|
|
@ -355,10 +380,29 @@ pub fn make_component(item: TokenStream) -> TokenStream {
|
||||||
|
|
||||||
// fn new
|
// fn new
|
||||||
|
|
||||||
component_impl_stream.extend(TokenStream::from(quote!(fn new(attrs: Self::ComponentAttrs) -> Self)));
|
component_impl_stream.extend(TokenStream::from(quote!(fn new(attrs: Self::ComponentAttrs, selfref: rusalka::WeakSharedComponent<Self>) -> Self)));
|
||||||
|
|
||||||
let mut new_stream = TokenStream::new();
|
let mut new_stream = TokenStream::new();
|
||||||
|
|
||||||
|
for variable in &reactive_variables {
|
||||||
|
new_stream.extend(TokenStream::from(quote!(let)));
|
||||||
|
new_stream.extend(Some(TokenTree::Ident(variable.name.clone())));
|
||||||
|
new_stream.extend(TokenStream::from(quote!(:)));
|
||||||
|
// new_stream.extend(TokenStream::from(quote!(Arc::new(Mutex::new(Invalidator::new)))));
|
||||||
|
|
||||||
|
let mut invalidator = TokenStream::from(quote!(rusalka::invalidator::Invalidator::new));
|
||||||
|
let mut invalidator_inner = TokenStream::new();
|
||||||
|
if let Some(def) = &variable.default {
|
||||||
|
invalidator_inner.extend(def.clone());
|
||||||
|
} else {
|
||||||
|
invalidator_inner.extend(TokenStream::from(quote!(Default::default())));
|
||||||
|
}
|
||||||
|
invalidator.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Parenthesis, invalidator_inner))));
|
||||||
|
new_stream.extend(wrap_in_arc_mutex(invalidator));
|
||||||
|
|
||||||
|
new_stream.extend(TokenStream::from(quote!(;)));
|
||||||
|
}
|
||||||
|
|
||||||
new_stream.extend(main_logic);
|
new_stream.extend(main_logic);
|
||||||
|
|
||||||
new_stream.extend(TokenStream::from(quote!(Self)));
|
new_stream.extend(TokenStream::from(quote!(Self)));
|
||||||
|
|
@ -369,7 +413,6 @@ pub fn make_component(item: TokenStream) -> TokenStream {
|
||||||
for component in &components_used {
|
for component in &components_used {
|
||||||
let ident = Ident::new(&format!("comp{}", i), Span::call_site());
|
let ident = Ident::new(&format!("comp{}", i), Span::call_site());
|
||||||
let component_name = component.name.clone();
|
let component_name = component.name.clone();
|
||||||
dbg!(&component_name);
|
|
||||||
|
|
||||||
new_returnvalue_stream.extend(Some(TokenTree::Ident(ident)));
|
new_returnvalue_stream.extend(Some(TokenTree::Ident(ident)));
|
||||||
new_returnvalue_stream.extend(TokenStream::from(quote!(:)));
|
new_returnvalue_stream.extend(TokenStream::from(quote!(:)));
|
||||||
|
|
@ -395,11 +438,13 @@ pub fn make_component(item: TokenStream) -> TokenStream {
|
||||||
|
|
||||||
component_new_stream.extend(Some(TokenTree::Group(components_attributes_group)));
|
component_new_stream.extend(Some(TokenTree::Group(components_attributes_group)));
|
||||||
|
|
||||||
|
component_new_stream.extend(TokenStream::from(quote!(, cselfref.clone())));
|
||||||
|
|
||||||
let component_new_group = Group::new(proc_macro::Delimiter::Parenthesis, component_new_stream);
|
let component_new_group = Group::new(proc_macro::Delimiter::Parenthesis, component_new_stream);
|
||||||
|
|
||||||
component_stream.extend(Some(TokenTree::Group(component_new_group)));
|
component_stream.extend(Some(TokenTree::Group(component_new_group)));
|
||||||
|
|
||||||
new_returnvalue_stream.extend(wrap_in_arcmutex(component_stream));
|
new_returnvalue_stream.extend(wrap_in_arcmutex_cyclic(component_stream));
|
||||||
},
|
},
|
||||||
ComponentType::Node => {
|
ComponentType::Node => {
|
||||||
let node_group = Group::new(proc_macro::Delimiter::Brace, component.contents.clone());
|
let node_group = Group::new(proc_macro::Delimiter::Brace, component.contents.clone());
|
||||||
|
|
@ -412,7 +457,7 @@ pub fn make_component(item: TokenStream) -> TokenStream {
|
||||||
i+=1;
|
i+=1;
|
||||||
}
|
}
|
||||||
|
|
||||||
new_returnvalue_stream.extend(TokenStream::from(quote!(attrs)));
|
new_returnvalue_stream.extend(TokenStream::from(quote!(attrs, selfref)));
|
||||||
|
|
||||||
let new_returnvalue_group = Group::new(proc_macro::Delimiter::Brace, new_returnvalue_stream);
|
let new_returnvalue_group = Group::new(proc_macro::Delimiter::Brace, new_returnvalue_stream);
|
||||||
new_stream.extend(Some(TokenTree::Group(new_returnvalue_group)));
|
new_stream.extend(Some(TokenTree::Group(new_returnvalue_group)));
|
||||||
|
|
@ -483,11 +528,10 @@ pub fn make_component(item: TokenStream) -> TokenStream {
|
||||||
|
|
||||||
match component.component_type {
|
match component.component_type {
|
||||||
ComponentType::RealComponent => {
|
ComponentType::RealComponent => {
|
||||||
let mut component_stream = TokenStream::new();
|
// mount
|
||||||
|
mount_stream.extend(TokenStream::from(quote!(self.)));
|
||||||
component_stream.extend(TokenStream::from(quote!(self.)));
|
mount_stream.extend(Some(TokenTree::Ident(ident)));
|
||||||
component_stream.extend(Some(TokenTree::Ident(ident)));
|
mount_stream.extend(TokenStream::from(quote!(.lock().unwrap().mount)));
|
||||||
component_stream.extend(TokenStream::from(quote!(.lock().unwrap().mount)));
|
|
||||||
|
|
||||||
let mut component_mount_stream = TokenStream::new();
|
let mut component_mount_stream = TokenStream::new();
|
||||||
|
|
||||||
|
|
@ -514,9 +558,8 @@ pub fn make_component(item: TokenStream) -> TokenStream {
|
||||||
|
|
||||||
let component_mount_group = Group::new(proc_macro::Delimiter::Parenthesis, component_mount_stream);
|
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(Some(TokenTree::Group(component_mount_group)));
|
||||||
|
|
||||||
mount_stream.extend(component_stream);
|
|
||||||
mount_stream.extend(TokenStream::from(quote!(;)));
|
mount_stream.extend(TokenStream::from(quote!(;)));
|
||||||
},
|
},
|
||||||
ComponentType::Node => {
|
ComponentType::Node => {
|
||||||
|
|
@ -605,10 +648,13 @@ pub fn make_component(item: TokenStream) -> TokenStream {
|
||||||
|
|
||||||
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);
|
dbg!(attributes);
|
||||||
|
|
||||||
|
dbg!(reactive_variables);
|
||||||
|
|
||||||
println!("{}", output.to_string());
|
println!("{}", output.to_string());
|
||||||
|
|
||||||
println!();
|
println!();
|
||||||
|
|
@ -616,12 +662,12 @@ pub fn make_component(item: TokenStream) -> TokenStream {
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrap_in_arcmutex(stream: TokenStream) -> TokenStream {
|
fn wrap_in_arc_mutex(stream: TokenStream) -> TokenStream {
|
||||||
let mut output = TokenStream::new();
|
let mut output = TokenStream::new();
|
||||||
|
|
||||||
output.extend(TokenStream::from(quote!(std::sync::Arc::new)));
|
output.extend(TokenStream::from(quote!(std::sync::Arc::new)));
|
||||||
|
|
||||||
let mut mutex_group = Group::new(proc_macro::Delimiter::Parenthesis, stream);
|
let mutex_group = Group::new(proc_macro::Delimiter::Parenthesis, stream);
|
||||||
|
|
||||||
let mut mutex_stream = TokenStream::new();
|
let mut mutex_stream = TokenStream::new();
|
||||||
|
|
||||||
|
|
@ -636,20 +682,42 @@ fn wrap_in_arcmutex(stream: TokenStream) -> TokenStream {
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn wrap_in_arcmutex_cyclic(stream: TokenStream) -> TokenStream {
|
||||||
|
let mut output = TokenStream::new();
|
||||||
|
|
||||||
|
output.extend(TokenStream::from(quote!(std::sync::Arc::new_cyclic)));
|
||||||
|
|
||||||
|
let mutex_group = Group::new(proc_macro::Delimiter::Parenthesis, stream);
|
||||||
|
|
||||||
|
let mut mutex_stream = TokenStream::new();
|
||||||
|
|
||||||
|
mutex_stream.extend(TokenStream::from(quote!(|cselfref|)));
|
||||||
|
|
||||||
|
mutex_stream.extend(TokenStream::from(quote!(std::sync::Mutex::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
|
||||||
|
}
|
||||||
|
|
||||||
fn wrap_in_arcrwlock(stream: TokenStream) -> TokenStream {
|
fn wrap_in_arcrwlock(stream: TokenStream) -> TokenStream {
|
||||||
let mut output = TokenStream::new();
|
let mut output = TokenStream::new();
|
||||||
|
|
||||||
output.extend(TokenStream::from(quote!(std::sync::Arc::new)));
|
output.extend(TokenStream::from(quote!(std::sync::Arc::new)));
|
||||||
|
|
||||||
let mut mutex_group = Group::new(proc_macro::Delimiter::Parenthesis, stream);
|
let mutex_group = Group::new(proc_macro::Delimiter::Parenthesis, stream);
|
||||||
|
|
||||||
let mut mutex_stream = TokenStream::new();
|
let mut rwlock_stream = TokenStream::new();
|
||||||
|
|
||||||
mutex_stream.extend(TokenStream::from(quote!(std::sync::RwLock::new)));
|
rwlock_stream.extend(TokenStream::from(quote!(std::sync::RwLock::new)));
|
||||||
|
|
||||||
mutex_stream.extend(Some(TokenTree::Group(mutex_group)));
|
rwlock_stream.extend(Some(TokenTree::Group(mutex_group)));
|
||||||
|
|
||||||
let arc_group = Group::new(proc_macro::Delimiter::Parenthesis, mutex_stream);
|
let arc_group = Group::new(proc_macro::Delimiter::Parenthesis, rwlock_stream);
|
||||||
|
|
||||||
output.extend(Some(TokenTree::Group(arc_group)));
|
output.extend(Some(TokenTree::Group(arc_group)));
|
||||||
|
|
||||||
|
|
@ -681,47 +749,64 @@ fn parse_components(name: Ident, group: Group, next: usize, parent: Option<usize
|
||||||
} else { name },
|
} else { name },
|
||||||
contents: self_stream.clone(),
|
contents: self_stream.clone(),
|
||||||
parent,
|
parent,
|
||||||
component_type: if name_starts_lowercase { ComponentType::Node } else { ComponentType::RealComponent }
|
component_type: if name_starts_lowercase { ComponentType::Node } else { ComponentType::RealComponent },
|
||||||
|
event_listeners: Vec::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
components_found.push(this_component);
|
components_found.push(this_component);
|
||||||
|
|
||||||
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() == '@' => {
|
||||||
if punct.as_char() == '@' {
|
let ident = group.next().unwrap();
|
||||||
let ident = group.next().unwrap();
|
let ident = match ident {
|
||||||
let ident = match ident {
|
TokenTree::Ident(ident) => ident,
|
||||||
TokenTree::Ident(ident) => ident,
|
_ => panic!("Expected ident after @")
|
||||||
_ => panic!("Expected ident after @")
|
};
|
||||||
};
|
|
||||||
|
|
||||||
let group = group.next().unwrap();
|
let group = group.next().unwrap();
|
||||||
let group = match group {
|
let group = match group {
|
||||||
TokenTree::Group(group) => group,
|
TokenTree::Group(group) => group,
|
||||||
_ => panic!("Expected group after ident")
|
_ => panic!("Expected group after ident")
|
||||||
};
|
};
|
||||||
|
|
||||||
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 {
|
},
|
||||||
self_stream.extend(Some(TokenTree::Punct(punct)));
|
TokenTree::Punct(punct) if punct.as_char() == '$' => {
|
||||||
while let Some(token) = group.next() {
|
// event handler
|
||||||
match token {
|
let fn_start = group.next().unwrap();
|
||||||
TokenTree::Punct(punct) => {
|
match fn_start {
|
||||||
if punct.as_char() == ',' {
|
TokenTree::Punct(punct) if punct.as_char() == '|' => {},
|
||||||
break;
|
_ => panic!("Expected | after $ (event handlers). Move is added automatically")
|
||||||
} else {
|
|
||||||
self_stream.extend(Some(TokenTree::Punct(punct)));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
self_stream.extend(Some(token));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
let fn_param = group.next().unwrap();
|
||||||
|
let fn_param = match fn_param {
|
||||||
|
TokenTree::Ident(ident) => ident,
|
||||||
|
_ => panic!("Expected ident after |")
|
||||||
|
};
|
||||||
|
let fn_end = group.next().unwrap();
|
||||||
|
match fn_end {
|
||||||
|
TokenTree::Punct(punct) if punct.as_char() == '|' => {},
|
||||||
|
_ => panic!("Expected | after fn param")
|
||||||
|
}
|
||||||
|
|
||||||
|
let fn_group = group.next().unwrap();
|
||||||
|
let fn_group = match fn_group {
|
||||||
|
TokenTree::Group(group) => group,
|
||||||
|
_ => panic!("Expected group after |param|")
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut callback_stream = TokenStream::from(quote!(move |#));
|
||||||
|
callback_stream.extend(Some(TokenTree::Ident(fn_param)));
|
||||||
|
callback_stream.extend(TokenStream::from(quote!(|)));
|
||||||
|
callback_stream.extend(Some(TokenTree::Group(fn_group)));
|
||||||
|
|
||||||
|
|
||||||
|
let this_component = components_found.get_mut(next).unwrap();
|
||||||
|
this_component.event_listeners.push(EventListener {
|
||||||
|
callback: callback_stream
|
||||||
|
});
|
||||||
},
|
},
|
||||||
any => {
|
any => {
|
||||||
// skip until next ',', writing to self_stream
|
// skip until next ',', writing to self_stream
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,19 @@
|
||||||
use mangui::{SharedNode, nodes::Node};
|
use mangui::{SharedNode, nodes::Node};
|
||||||
|
|
||||||
|
use crate::WeakSharedComponent;
|
||||||
|
|
||||||
/// A rusalka component
|
/// A rusalka component
|
||||||
pub trait Component {
|
pub trait Component {
|
||||||
type ComponentAttrs: Default;
|
type ComponentAttrs: Default;
|
||||||
type PartialComponentAttrs: Default + From<Self::ComponentAttrs>;
|
type PartialComponentAttrs: Default + From<Self::ComponentAttrs>;
|
||||||
const UPDATE_LENGTH : usize = 0;
|
const UPDATE_LENGTH : usize = 0;
|
||||||
fn new(attr: Self::ComponentAttrs) -> Self;
|
fn new(attr: Self::ComponentAttrs, selfref: WeakSharedComponent<Self>) -> Self;
|
||||||
fn get(&self) -> &Self::ComponentAttrs;
|
fn get(&self) -> &Self::ComponentAttrs;
|
||||||
fn set(&mut self, attr: Self::PartialComponentAttrs);
|
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, bitmap: &[u32]);
|
fn update(&self, bitmap: &[u32]);
|
||||||
fn unmount(&self);
|
fn unmount(&self);
|
||||||
|
// fn set_selfref(&mut self, selfref: SharedComponent<Self>);
|
||||||
|
|
||||||
fn check_update(&self, bitmap: &[u32]) -> () {
|
fn check_update(&self, bitmap: &[u32]) -> () {
|
||||||
if bitmap.len() != Self::UPDATE_LENGTH {
|
if bitmap.len() != Self::UPDATE_LENGTH {
|
||||||
|
|
|
||||||
36
rusalka/src/invalidator.rs
Normal file
36
rusalka/src/invalidator.rs
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
|
pub struct Invalidator<T> {
|
||||||
|
inner: T,
|
||||||
|
invalidated: bool
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Invalidator<T> {
|
||||||
|
pub fn new(inner: T) -> Self {
|
||||||
|
Self {
|
||||||
|
inner,
|
||||||
|
invalidated: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn reset(&mut self) {
|
||||||
|
self.invalidated = false;
|
||||||
|
}
|
||||||
|
pub fn invalidated(&self) -> bool {
|
||||||
|
self.invalidated
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Deref for Invalidator<T> {
|
||||||
|
type Target = T;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> DerefMut for Invalidator<T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
self.invalidated = true;
|
||||||
|
&mut self.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -5,6 +5,8 @@ use mangui::nodes::Node;
|
||||||
|
|
||||||
pub mod component;
|
pub mod component;
|
||||||
pub mod nodes;
|
pub mod nodes;
|
||||||
|
pub mod invalidator;
|
||||||
|
|
||||||
pub type SharedComponent<T: Component> = Arc<Mutex<T>>;
|
pub type SharedComponent<T: Component> = Arc<Mutex<T>>;
|
||||||
|
pub type WeakSharedComponent<T: Component> = std::sync::Weak<Mutex<T>>;
|
||||||
pub type SharedNodeComponent<T: Node> = Arc<RwLock<T>>;
|
pub type SharedNodeComponent<T: Node> = Arc<RwLock<T>>;
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
fn main() {
|
|
||||||
println!("Hello, world!");
|
|
||||||
}
|
|
||||||
|
|
@ -4,13 +4,14 @@
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use mangui::{SharedNode, nodes::{primitives, Style}, taffy::prelude::Size, femtovg::{Paint, Color}};
|
use mangui::{SharedNode, nodes::{primitives, Style}, taffy::prelude::Size, femtovg::{Paint, Color}};
|
||||||
|
|
||||||
use crate::component::Component;
|
use crate::{component::Component, SharedComponent, WeakSharedComponent};
|
||||||
|
|
||||||
use super::{insert, detach};
|
use super::{insert, detach};
|
||||||
|
|
||||||
pub struct Rectangle {
|
pub struct Rectangle {
|
||||||
node: Arc<RwLock<primitives::Rectangle>>,
|
node: Arc<RwLock<primitives::Rectangle>>,
|
||||||
attrs: RectangleAttributes
|
attrs: RectangleAttributes,
|
||||||
|
selfref: WeakSharedComponent<Self>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
@ -36,7 +37,7 @@ impl Component for Rectangle {
|
||||||
type ComponentAttrs = RectangleAttributes;
|
type ComponentAttrs = RectangleAttributes;
|
||||||
type PartialComponentAttrs = PartialRectangleAttributes;
|
type PartialComponentAttrs = PartialRectangleAttributes;
|
||||||
const UPDATE_LENGTH : usize = 1;
|
const UPDATE_LENGTH : usize = 1;
|
||||||
fn new(attrs: Self::ComponentAttrs) -> Self {
|
fn new(attrs: Self::ComponentAttrs, selfref: WeakSharedComponent<Self>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
node: Arc::new(RwLock::new(primitives::Rectangle {
|
node: Arc::new(RwLock::new(primitives::Rectangle {
|
||||||
style: Style {
|
style: Style {
|
||||||
|
|
@ -53,7 +54,8 @@ impl Component for Rectangle {
|
||||||
radius: attrs.radius,
|
radius: attrs.radius,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})),
|
})),
|
||||||
attrs
|
attrs,
|
||||||
|
selfref
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue