mirror of
https://github.com/danbulant/mangui
synced 2026-06-21 07:31:49 +00:00
WIP rusalka compiler
This commit is contained in:
parent
55476f971f
commit
38473da15f
15 changed files with 633 additions and 73 deletions
16
Cargo.lock
generated
16
Cargo.lock
generated
|
|
@ -641,6 +641,8 @@ name = "mangades"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"mangui",
|
||||
"rusalka",
|
||||
"rusalka-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -935,6 +937,20 @@ dependencies = [
|
|||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rusalka"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"mangui",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rusalka-macro"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"quote",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.20"
|
||||
|
|
|
|||
|
|
@ -3,5 +3,7 @@ package.authors = ["Daniel Bulant"]
|
|||
resolver = "2"
|
||||
members = [
|
||||
"ui",
|
||||
"mangades"
|
||||
"mangades",
|
||||
"rusalka",
|
||||
"rusalka-macro"
|
||||
]
|
||||
|
|
@ -6,4 +6,6 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
mangui = { path = "../ui"}
|
||||
mangui = { path = "../ui"}
|
||||
rusalka = { path = "../rusalka"}
|
||||
rusalka-macro = { path = "../rusalka-macro"}
|
||||
|
|
|
|||
32
mangades/src/component_demo.rs
Normal file
32
mangades/src/component_demo.rs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
use std::sync::{Arc, Mutex};
|
||||
use mangui::SharedNode;
|
||||
use rusalka::{component::Component, nodes::primitives::{Rectangle, RectangleAttributes}, SharedComponent};
|
||||
|
||||
pub struct DemoComponent {
|
||||
rect: SharedComponent<Rectangle>,
|
||||
attrs: DemoComponentAttributes,
|
||||
}
|
||||
|
||||
pub struct DemoComponentAttributes {}
|
||||
|
||||
impl Component for DemoComponent {
|
||||
type ComponentAttrs = DemoComponentAttributes;
|
||||
fn new(attrs: Self::ComponentAttrs) -> Self {
|
||||
Self {
|
||||
rect: Arc::new(Mutex::new(Rectangle::new(RectangleAttributes {}))),
|
||||
attrs,
|
||||
}
|
||||
}
|
||||
|
||||
fn set(&mut self, attrs: Self::ComponentAttrs) { self.attrs = attrs; }
|
||||
fn get(&self) -> &Self::ComponentAttrs { &self.attrs }
|
||||
fn mount(&self, parent: &SharedNode, before: Option<&SharedNode>) {
|
||||
self.rect.lock().unwrap().mount(parent, before);
|
||||
}
|
||||
|
||||
fn unmount(&self) {
|
||||
self.rect.lock().unwrap().unmount();
|
||||
}
|
||||
|
||||
fn update(&self) {}
|
||||
}
|
||||
29
mangades/src/component_demo_syntax.rs
Normal file
29
mangades/src/component_demo_syntax.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
use rusalka_macro::make_component;
|
||||
use std::default::Default;
|
||||
use mangui::{SharedNode, nodes::Style, taffy::prelude::Size, femtovg::{Paint, Color}};
|
||||
|
||||
use rusalka::nodes::primitives::{Rectangle, RectangleAttributes};
|
||||
|
||||
make_component!(
|
||||
ComponentDemo,
|
||||
Logic {
|
||||
let test = false;
|
||||
}
|
||||
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()
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
@ -2,76 +2,15 @@ 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};
|
||||
|
||||
mod component_demo;
|
||||
mod component_demo_syntax;
|
||||
|
||||
fn main() {
|
||||
let (tx, rx) = mpsc::channel();
|
||||
let tx = Arc::new(tx);
|
||||
let _tx = Arc::new(tx);
|
||||
let mut root = Layout::default();
|
||||
root.style.layout.display = taffy::style::Display::Flex;
|
||||
root.style.layout.flex_direction = taffy::style::FlexDirection::Row;
|
||||
root.children.push(Arc::new(RwLock::new(nodes::primitives::Rectangle {
|
||||
style: Style {
|
||||
overflow: nodes::Overflow::Visible,
|
||||
layout: TaffyStyle {
|
||||
min_size: Size {
|
||||
width: Dimension::Points(100.),
|
||||
height: Dimension::Points(100.)
|
||||
},
|
||||
..Default::default()
|
||||
}
|
||||
},
|
||||
fill: Paint::color(Color::rgb(255, 0, 0)),
|
||||
radius: 10.,
|
||||
events: Default::default()
|
||||
})));
|
||||
root.children.push(Arc::new(RwLock::new(Layout {
|
||||
style: Style {
|
||||
overflow: nodes::Overflow::Visible,
|
||||
layout: TaffyStyle {
|
||||
min_size: Size {
|
||||
width: Dimension::Points(100.),
|
||||
height: Dimension::Points(100.)
|
||||
},
|
||||
flex_grow: 1.,
|
||||
display: taffy::style::Display::Flex,
|
||||
flex_direction: taffy::style::FlexDirection::Column,
|
||||
..Default::default()
|
||||
}
|
||||
},
|
||||
children: vec![
|
||||
Arc::new(RwLock::new(nodes::primitives::Rectangle {
|
||||
style: Style {
|
||||
overflow: nodes::Overflow::Visible,
|
||||
layout: TaffyStyle {
|
||||
min_size: Size {
|
||||
width: Dimension::Points(50.),
|
||||
height: Dimension::Points(50.)
|
||||
},
|
||||
flex_grow: 1.,
|
||||
..Default::default()
|
||||
}
|
||||
},
|
||||
fill: Paint::color(Color::rgb(0, 255, 0)),
|
||||
radius: 5.,
|
||||
events: Default::default()
|
||||
})),
|
||||
Arc::new(RwLock::new(nodes::primitives::Rectangle {
|
||||
style: Style {
|
||||
overflow: nodes::Overflow::Visible,
|
||||
layout: TaffyStyle {
|
||||
min_size: Size {
|
||||
width: Dimension::Points(50.),
|
||||
height: Dimension::Points(50.)
|
||||
},
|
||||
..Default::default()
|
||||
}
|
||||
},
|
||||
fill: Paint::color(Color::rgb(0, 255, 255)),
|
||||
radius: 5.,
|
||||
events: Default::default()
|
||||
}))
|
||||
],
|
||||
events: Default::default()
|
||||
})));
|
||||
let right_node = Arc::new(RwLock::new(nodes::primitives::Rectangle {
|
||||
style: Style {
|
||||
overflow: nodes::Overflow::Visible,
|
||||
|
|
@ -81,11 +20,13 @@ fn main() {
|
|||
height: Dimension::Points(100.)
|
||||
},
|
||||
..Default::default()
|
||||
}
|
||||
},
|
||||
cursor: Default::default()
|
||||
},
|
||||
fill: Paint::color(Color::rgb(0, 0, 255)),
|
||||
radius: 0.,
|
||||
events: Default::default()
|
||||
events: Default::default(),
|
||||
parent: None
|
||||
}));
|
||||
root.children.push(right_node.clone());
|
||||
right_node.clone().write().unwrap().events.add_handler(Box::new(move |event| {
|
||||
|
|
|
|||
13
rusalka-macro/Cargo.toml
Normal file
13
rusalka-macro/Cargo.toml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
[package]
|
||||
name = "rusalka-macro"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
authors.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
quote = "1.0"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
410
rusalka-macro/src/lib.rs
Normal file
410
rusalka-macro/src/lib.rs
Normal file
|
|
@ -0,0 +1,410 @@
|
|||
use proc_macro::{TokenStream, TokenTree, Ident, Group, Punct, Span};
|
||||
use quote::quote;
|
||||
|
||||
struct Attribute {
|
||||
name: Ident,
|
||||
default: Option<TokenStream>,
|
||||
type_: TokenStream
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ComponentUsed {
|
||||
name: Ident,
|
||||
contents: TokenStream,
|
||||
parent: Option<usize>
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn make_component(item: TokenStream) -> TokenStream {
|
||||
dbg!(&item);
|
||||
|
||||
let mut last_identifier = None;
|
||||
let mut item = item.into_iter();
|
||||
let name = item.next().unwrap();
|
||||
item.next().unwrap();
|
||||
let str_name = name.to_string();
|
||||
|
||||
dbg!(&name);
|
||||
|
||||
// let mut attributes: Vec<Attribute> = Vec::new();
|
||||
|
||||
// let mut struct_values = Vec::new();
|
||||
|
||||
let mut main_logic = Vec::new();
|
||||
|
||||
// let mut reactive_variables = Vec::new();
|
||||
|
||||
let mut components_used: Vec<ComponentUsed> = Vec::new();
|
||||
|
||||
for token in item {
|
||||
match token {
|
||||
TokenTree::Ident(ident) => {
|
||||
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);
|
||||
}
|
||||
},
|
||||
TokenTree::Group(group) => {
|
||||
match &last_identifier {
|
||||
Some(ident) => {
|
||||
match ident.as_str() {
|
||||
"Logic" => {
|
||||
main_logic.push(group.stream());
|
||||
},
|
||||
"Component" => {
|
||||
// Example syntax:
|
||||
// @Layout {
|
||||
// style: Style { ... },
|
||||
// @Rectangle {
|
||||
// fill: Paint::color(Color::rgb(0, 0, 255)),
|
||||
// }
|
||||
// @Rectangle {
|
||||
// fill: Paint::color(Color::rgb(0, 0, 255)),
|
||||
// }
|
||||
// }
|
||||
// non-component properties cannot contain components
|
||||
// top level must contain only components
|
||||
// components can contain components
|
||||
|
||||
let mut stream = group.stream().into_iter();
|
||||
|
||||
while let Some(token) = stream.next() {
|
||||
match token {
|
||||
TokenTree::Punct(punct) => {
|
||||
if punct.as_char() != '@' {
|
||||
panic!("Expected @");
|
||||
}
|
||||
},
|
||||
_ => panic!("Expected @")
|
||||
};
|
||||
|
||||
let ident = stream.next().unwrap();
|
||||
let ident = match ident {
|
||||
TokenTree::Ident(ident) => ident,
|
||||
_ => panic!("Expected ident after @")
|
||||
};
|
||||
|
||||
let group = stream.next().unwrap();
|
||||
let group = match group {
|
||||
TokenTree::Group(group) => group,
|
||||
_ => panic!("Expected group after ident")
|
||||
};
|
||||
|
||||
let components = parse_components(ident, group, components_used.len(), None);
|
||||
components_used.extend(components);
|
||||
}
|
||||
|
||||
},
|
||||
_ => unreachable!()
|
||||
}
|
||||
},
|
||||
None => {
|
||||
panic!("Unexpected group: {:?}", group);
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
panic!("Unknown token: {:?}", token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dbg!(&components_used);
|
||||
|
||||
let mut output = TokenStream::new();
|
||||
|
||||
// Component struct
|
||||
|
||||
output.extend(TokenStream::from(quote!(pub struct)));
|
||||
output.extend(Some(name.clone()));
|
||||
|
||||
let mut component_struct_stream = TokenStream::new();
|
||||
|
||||
let mut i = 0;
|
||||
for component in &components_used {
|
||||
|
||||
let ident = Ident::new(&format!("comp{}", i), Span::call_site());
|
||||
|
||||
let midstream = TokenStream::from(quote!(: rusalka::SharedComponent<));
|
||||
|
||||
let component_name = component.name.clone();
|
||||
|
||||
component_struct_stream.extend(Some(TokenTree::Ident(ident)));
|
||||
component_struct_stream.extend(midstream);
|
||||
component_struct_stream.extend(Some(TokenTree::Ident(component_name)));
|
||||
component_struct_stream.extend(TokenStream::from(quote!(>,)));
|
||||
|
||||
i+=1;
|
||||
}
|
||||
|
||||
// Attributes struct
|
||||
|
||||
let attributes_ident = Ident::new(&format!("{str_name}Attributes"), Span::call_site());
|
||||
|
||||
component_struct_stream.extend(TokenStream::from(quote!(attrs: )));
|
||||
component_struct_stream.extend(Some(TokenTree::Ident(attributes_ident.clone())));
|
||||
|
||||
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)));
|
||||
output.extend(Some(TokenTree::Ident(attributes_ident.clone())));
|
||||
output.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Brace, attributes_struct_stream))));
|
||||
|
||||
// Component impl
|
||||
|
||||
output.extend(TokenStream::from(quote!(impl rusalka::component::Component for)));
|
||||
output.extend(Some(name.clone()));
|
||||
|
||||
let mut component_impl_stream = TokenStream::new();
|
||||
|
||||
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!(;)));
|
||||
|
||||
// fn new
|
||||
|
||||
component_impl_stream.extend(TokenStream::from(quote!(fn new(attrs: Self::ComponentAttrs) -> Self)));
|
||||
|
||||
let mut new_stream = TokenStream::new();
|
||||
|
||||
new_stream.extend(main_logic);
|
||||
|
||||
new_stream.extend(TokenStream::from(quote!(Self)));
|
||||
|
||||
let mut new_returnvalue_stream = TokenStream::new();
|
||||
|
||||
i = 0;
|
||||
for component in &components_used {
|
||||
let ident = Ident::new(&format!("comp{}", i), Span::call_site());
|
||||
let component_name = component.name.clone();
|
||||
dbg!(&component_name);
|
||||
|
||||
new_returnvalue_stream.extend(Some(TokenTree::Ident(ident)));
|
||||
new_returnvalue_stream.extend(TokenStream::from(quote!(:)));
|
||||
|
||||
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();
|
||||
|
||||
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));
|
||||
new_returnvalue_stream.extend(TokenStream::from(quote!(,)));
|
||||
|
||||
i+=1;
|
||||
}
|
||||
|
||||
new_returnvalue_stream.extend(TokenStream::from(quote!(attrs)));
|
||||
|
||||
let new_returnvalue_group = Group::new(proc_macro::Delimiter::Brace, new_returnvalue_stream);
|
||||
new_stream.extend(Some(TokenTree::Group(new_returnvalue_group)));
|
||||
|
||||
let new_group = Group::new(proc_macro::Delimiter::Brace, new_stream);
|
||||
component_impl_stream.extend(Some(TokenTree::Group(new_group)));
|
||||
|
||||
// fn set
|
||||
|
||||
component_impl_stream.extend(TokenStream::from(quote!(fn set(&mut self, attrs: Self::ComponentAttrs) { self.attrs = attrs; })));
|
||||
|
||||
// fn get
|
||||
|
||||
component_impl_stream.extend(TokenStream::from(quote!(fn get(&self) -> &Self::ComponentAttrs { &self.attrs })));
|
||||
|
||||
// fn mount
|
||||
|
||||
component_impl_stream.extend(TokenStream::from(quote!(fn mount(&self, parent: &mangui::SharedNode, before: Option<&mangui::SharedNode>))));
|
||||
|
||||
let mut mount_stream = TokenStream::new();
|
||||
|
||||
for i in 0..components_used.len() {
|
||||
let ident = Ident::new(&format!("comp{}", i), Span::call_site());
|
||||
|
||||
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_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!(;)));
|
||||
}
|
||||
|
||||
let mount_group = Group::new(proc_macro::Delimiter::Brace, mount_stream);
|
||||
component_impl_stream.extend(Some(TokenTree::Group(mount_group)));
|
||||
|
||||
// fn unmount
|
||||
|
||||
component_impl_stream.extend(TokenStream::from(quote!(fn unmount(&self))));
|
||||
|
||||
let mut unmount_stream = TokenStream::new();
|
||||
|
||||
for i in 0..components_used.len() {
|
||||
let ident = Ident::new(&format!("comp{}", i), Span::call_site());
|
||||
|
||||
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!(;)));
|
||||
}
|
||||
|
||||
let unmount_group = Group::new(proc_macro::Delimiter::Brace, unmount_stream);
|
||||
component_impl_stream.extend(Some(TokenTree::Group(unmount_group)));
|
||||
|
||||
// fn update
|
||||
|
||||
component_impl_stream.extend(TokenStream::from(quote!(fn update(&self) {})));
|
||||
|
||||
output.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Brace, component_impl_stream))));
|
||||
|
||||
dbg!(&output);
|
||||
|
||||
println!("{}", output.to_string());
|
||||
|
||||
println!();
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
fn wrap_in_arcmutex(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::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
|
||||
}
|
||||
|
||||
/// Call this after @
|
||||
/// Will return the main component as well as any sub-components
|
||||
/// name: the name of the component
|
||||
/// group: the group of tokens that make up the component
|
||||
/// next: the index of this component in the components_used vector
|
||||
/// parent: the index of the parent component in the components_used vector
|
||||
fn parse_components(name: Ident, group: Group, next: usize, parent: Option<usize>) -> Vec<ComponentUsed> {
|
||||
let mut components_found = Vec::new();
|
||||
|
||||
let mut group = group.stream().into_iter();
|
||||
let mut self_stream = TokenStream::new();
|
||||
|
||||
// dbg!(&name);
|
||||
|
||||
let this_component = ComponentUsed {
|
||||
name,
|
||||
contents: self_stream.clone(),
|
||||
parent
|
||||
};
|
||||
|
||||
|
||||
components_found.push(this_component);
|
||||
|
||||
while let Some(token) = group.next() {
|
||||
match token {
|
||||
TokenTree::Punct(punct) => {
|
||||
if punct.as_char() == '@' {
|
||||
let ident = group.next().unwrap();
|
||||
let ident = match ident {
|
||||
TokenTree::Ident(ident) => ident,
|
||||
_ => panic!("Expected ident after @")
|
||||
};
|
||||
|
||||
let group = group.next().unwrap();
|
||||
let group = match group {
|
||||
TokenTree::Group(group) => group,
|
||||
_ => panic!("Expected group after ident")
|
||||
};
|
||||
|
||||
let components = parse_components(ident, group, next + components_found.len() + 1, Some(next));
|
||||
components_found.extend(components);
|
||||
} else {
|
||||
while let Some(token) = group.next() {
|
||||
match token {
|
||||
TokenTree::Punct(punct) => {
|
||||
if punct.as_char() == ',' {
|
||||
break;
|
||||
} else {
|
||||
self_stream.extend(Some(TokenTree::Punct(punct)));
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
self_stream.extend(Some(token));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
// skip until next ',', writing to self_stream
|
||||
|
||||
while let Some(token) = group.next() {
|
||||
match token {
|
||||
TokenTree::Punct(punct) => {
|
||||
if punct.as_char() == ',' {
|
||||
break;
|
||||
} else {
|
||||
self_stream.extend(Some(TokenTree::Punct(punct)));
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
self_stream.extend(Some(token));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
components_found.get_mut(0).unwrap().contents = self_stream;
|
||||
|
||||
components_found
|
||||
}
|
||||
10
rusalka/Cargo.toml
Normal file
10
rusalka/Cargo.toml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
[package]
|
||||
name = "rusalka"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
authors.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
mangui = { path = "../ui"}
|
||||
12
rusalka/src/component.rs
Normal file
12
rusalka/src/component.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
use mangui::SharedNode;
|
||||
|
||||
/// A rusalka component
|
||||
pub trait Component {
|
||||
type ComponentAttrs;
|
||||
fn new(attr: Self::ComponentAttrs) -> Self;
|
||||
fn get(&self) -> &Self::ComponentAttrs;
|
||||
fn set(&mut self, attr: Self::ComponentAttrs);
|
||||
fn mount(&self, parent: &SharedNode, before: Option<&SharedNode>);
|
||||
fn update(&self);
|
||||
fn unmount(&self);
|
||||
}
|
||||
8
rusalka/src/lib.rs
Normal file
8
rusalka/src/lib.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use component::Component;
|
||||
|
||||
pub mod component;
|
||||
pub mod nodes;
|
||||
|
||||
pub type SharedComponent<T: Component> = Arc<Mutex<T>>;
|
||||
3
rusalka/src/main.rs
Normal file
3
rusalka/src/main.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
29
rusalka/src/nodes/mod.rs
Normal file
29
rusalka/src/nodes/mod.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
use std::sync::Arc;
|
||||
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();
|
||||
}
|
||||
node.clone().write().unwrap().set_parent(None);
|
||||
}
|
||||
|
||||
pub fn insert(parent: &SharedNode, node: &SharedNode, before: Option<&SharedNode>) {
|
||||
match before {
|
||||
Some(before) => {
|
||||
parent.write().unwrap().add_child_before(node.clone(), before).unwrap();
|
||||
node.write().unwrap().set_parent(Some(Arc::downgrade(parent)));
|
||||
},
|
||||
None => {
|
||||
append(parent, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn append(parent: &SharedNode, node: &SharedNode) {
|
||||
parent.write().unwrap().add_child(node.clone()).unwrap();
|
||||
node.write().unwrap().set_parent(Some(Arc::downgrade(parent)));
|
||||
}
|
||||
53
rusalka/src/nodes/primitives.rs
Normal file
53
rusalka/src/nodes/primitives.rs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
|
||||
// DemoComponent
|
||||
|
||||
use std::sync::{Arc, RwLock};
|
||||
use mangui::{SharedNode, nodes::{primitives, Style}, taffy::prelude::Size, femtovg::{Paint, Color}};
|
||||
|
||||
use crate::component::Component;
|
||||
|
||||
use super::{insert, detach};
|
||||
|
||||
pub struct Rectangle {
|
||||
node: SharedNode,
|
||||
attrs: RectangleAttributes
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct RectangleAttributes {}
|
||||
|
||||
impl Component for Rectangle {
|
||||
type ComponentAttrs = RectangleAttributes;
|
||||
fn new(attrs: Self::ComponentAttrs) -> Self {
|
||||
Self {
|
||||
node: Arc::new(RwLock::new(primitives::Rectangle {
|
||||
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()
|
||||
},
|
||||
fill: Paint::color(Color::rgb(0, 0, 255)),
|
||||
radius: 5.,
|
||||
..Default::default()
|
||||
})),
|
||||
attrs
|
||||
}
|
||||
}
|
||||
|
||||
fn set(&mut self, attrs: Self::ComponentAttrs) { self.attrs = attrs; }
|
||||
fn get(&self) -> &Self::ComponentAttrs { &self.attrs }
|
||||
fn mount(&self, parent: &SharedNode, before: Option<&SharedNode>) {
|
||||
insert(parent, &self.node, before);
|
||||
}
|
||||
|
||||
fn update(&self) {}
|
||||
|
||||
fn unmount(&self) {
|
||||
detach(&self.node);
|
||||
}
|
||||
}
|
||||
|
|
@ -100,7 +100,7 @@ pub fn run_event_loop(entry: MainEntry) -> () {
|
|||
|
||||
event_loop.run(move |event, target| match event {
|
||||
Event::WindowEvent { event, .. } => match event {
|
||||
WindowEvent::MouseWheel { device_id, delta, phase, .. } => {},
|
||||
WindowEvent::MouseWheel { device_id: _, delta: _, phase: _, .. } => {},
|
||||
WindowEvent::CursorMoved { device_id, position, .. } => {
|
||||
let mouse_value = mouse_values.get(&device_id);
|
||||
let (movement, location, mouse_value) = match mouse_value {
|
||||
|
|
@ -152,8 +152,8 @@ pub fn run_event_loop(entry: MainEntry) -> () {
|
|||
window.request_redraw();
|
||||
}
|
||||
},
|
||||
WindowEvent::DroppedFile(path) => {},
|
||||
WindowEvent::HoveredFile(path) => {},
|
||||
WindowEvent::DroppedFile(_path) => {},
|
||||
WindowEvent::HoveredFile(_path) => {},
|
||||
WindowEvent::HoveredFileCancelled => {},
|
||||
WindowEvent::Focused(focused) => {
|
||||
match &focus_path {
|
||||
|
|
@ -184,7 +184,7 @@ pub fn run_event_loop(entry: MainEntry) -> () {
|
|||
};
|
||||
},
|
||||
WindowEvent::ModifiersChanged(new_modifiers) => { modifiers = new_modifiers; },
|
||||
WindowEvent::KeyboardInput { device_id, event, is_synthetic } => {},
|
||||
WindowEvent::KeyboardInput { device_id: _, event: _, is_synthetic: _ } => {},
|
||||
WindowEvent::MouseInput { device_id, state, button, .. } => {
|
||||
let mouse_value = mouse_values.get(&device_id);
|
||||
let mut mouse_value = match mouse_value {
|
||||
|
|
|
|||
Loading…
Reference in a new issue