vizia/morphorm

Morphorm ECS and serializing/deserializing

Closed this issue · 6 comments

Hi,

I'm trying to write a JSON serializer/deserializer for morphorm ECS, as part of trying to learn how to write my own library crates.
I'd like to be able to write my Kayak UI in a serialized format that is loaded.

So far I've been unable to access the morphorm_ecs crate. It doesn't seem to be available on crates.io?

[package]
name = "morphorm-serializer"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
morphorm = "0.3.0"
regex = "1.7.0"
serde = { version = "1.0.147", features = ["derive"] }
serde_json = "1.0.89"
use std::ops::Add;
use regex::Regex;

// use morphorm::Cache;
use morphorm::*;
use morphorm_ecs::*; // unresolved import
use serde_json;
use std::result::Result;
use std::error::Error;
use serde::{Deserialize, Serialize};


pub fn build_world(world: World, root: Entity, ui: UiNode) {
    let mut world = World::default();
    let root: Entity = world.add(None);
    build_node(world, root, ui);
}

// starting very simple, just trying to handle with and pixels unit    
pub fn build_node(world: World, node: Entity, ui: UiNode) {
    if let Some(str) = ui.width {
        let re = Regex::new(r"px$").unwrap();
        if re.is_match(str) {
           let number = str[..str.len() - 2];
            let pixels = number.parse::<f32>().unwrap();
            world.set_width(node, Units::Pixels(pixels));    
        }
    }
    dbg!(node)
}

type OptStr = Option<String>;
// type OptNum = Option<u32>;

#[derive(Debug, Serialize, Deserialize)]
pub struct UiNode {
   #[serde(skip_serializing_if = "Option::is_none")]
   width: OptStr,
   height: OptStr,
   child_space: OptStr,
   position_type: OptStr,
} 

pub fn parse_ui() -> Result<(), Box<dyn Error>> {

    let json1 = r#"
    {
        "width": "2 px",
        "height": "5 px"
    }
    "#;    

    let ui: UiNode = serde_json::from_str(json1)?;
    println!("ui {:#?}", ui);
    build_world(world, root, ui);

    Ok(())
}

I think I understand now that the ecs folder is just a sample use case and that I need to operate on Kayak UI directly?

I think I understand now that the ecs folder is just a sample use case and that I need to operate on Kayak UI directly?

Yes you are correct. The morphorm_ecs crate is purely for demonstration on how morphorm can be integrated with an ECS pattern such as bevy and I think kayak? I believe that you only need to operate on the kayak crate but if that's not the case then I can add serde as an optional feature and provide serialization for the morphorm types. Let me know.

Thanks. I'm currently working on a Kayak UI JSON deserializer here: https://github.com/kristianmandrup/kayak_ui_deserializer

I discovered that I will need a macro in order to build the UI objects conditionally

        let posx = self.posx();
        let posy = self.posy();
        let width = self.width();
        let height = self.height();
        let z_index = self.z_index();
        let rect = Rect {
            ..Default::default()
        };       
        if let Some(val) = posx {
             // no setter available
             rect.posx = val;    
        }

Will need to be replaced with something like the following if I understand correctly?

  rect! { posx, posy, width, height, z_index }

I discovered how to generalize it using a macro approach exactly as described here :)

https://www.ralphminderhoud.com/blog/simple-struct-macro/

    pub fn parse(&self) -> Result<Rect, &'static str> {        
        let posx = self.posx();
        // ... repeat
        let mut rect = Rect::default();

        // ... repeat: use macro!
        if let Some(val) = posx {
            rect.posx = val;    
        }

I discovered how to generalize it using a macro approach exactly as described here :)

https://www.ralphminderhoud.com/blog/simple-struct-macro/

    pub fn parse(&self) -> Result<Rect, &'static str> {        
        let posx = self.posx();
        // ... repeat
        let mut rect = Rect::default();

        // ... repeat: use macro!
        if let Some(val) = posx {
            rect.posx = val;    
        }

Ah that's great 👍 is this issue resolved then? Am I okay to close it?

Sure 😃