deft 1.0.0

Cross platform ui framework
use std::cell::RefCell;
use yoga::{Direction, Layout};
use crate::number::DeNan;
use crate::state::{State, StateManager};
use crate::style::YogaNode;

thread_local! {
    static NODE_MGR: RefCell<StateManager> = RefCell::new(StateManager::new());
}

struct LayoutNodeInfo {
    _yn: YogaNode,
    _shadow_yn: Option<YogaNode>,
    shadow_layout_calculated: bool,
}

impl LayoutNodeInfo {
    fn new(layout_node: YogaNode) -> LayoutNodeInfo {
        Self {
            _yn: layout_node,
            _shadow_yn: None,
            shadow_layout_calculated: false,
        }
    }
}

#[derive(Clone)]
pub struct LayoutNode {
    parent: Option<Box<LayoutNode>>,
    state: State<LayoutNodeInfo>,
    children: Vec<LayoutNode>,
}


impl LayoutNode {
    pub fn new(layout_node: YogaNode) -> LayoutNode {
        let state = NODE_MGR.with_borrow_mut(|mgr| mgr.new_state(LayoutNodeInfo::new(layout_node)));
        Self { state, parent: None, children: Vec::new() }
    }

    pub fn update_yn(&self, yn: YogaNode) -> anyhow::Result<()> {
        let mut state = self.state.upgrade()?;
        state._yn = yn;
        Ok(())
    }

    pub fn update_shadow_yn(&self, yn: Option<YogaNode>) -> anyhow::Result<()> {
        let mut state = self.state.upgrade()?;
        state._shadow_yn = yn;
        state.shadow_layout_calculated = false;
        Ok(())
    }

    pub fn get_yn(&self) -> anyhow::Result<YogaNode> {
        let state = self.state.upgrade()?;
        Ok(state._yn.clone())
    }

    pub fn get_padding(&self) -> anyhow::Result<[f32; 4]> {
        let state = self.state.upgrade()?;
        Ok([
            state._yn.get_layout_padding_top().de_nan(0.0),
            state._yn.get_layout_padding_right().de_nan(0.0),
            state._yn.get_layout_padding_bottom().de_nan(0.0),
            state._yn.get_layout_padding_left().de_nan(0.0),
        ])
    }

    pub fn get_shadow_size(&self) -> anyhow::Result<Option<(f32, f32)>> {
        let state = self.state.upgrade()?;
        let r = state._shadow_yn.as_ref()
            .map(|n| (n.get_layout_width(), n.get_layout_width()));
        Ok(r)
    }

    pub fn get_border(&self) -> anyhow::Result<[f32; 4]> {
        let state = self.state.upgrade()?;
        let bl = state._yn.get_layout_border_left().de_nan(0.0);
        let br = state._yn.get_layout_border_right().de_nan(0.0);
        let bt = state._yn.get_layout_border_top().de_nan(0.0);
        let bb = state._yn.get_layout_border_bottom().de_nan(0.0);
        Ok([bt, br, bb, bl])
    }

    pub fn get_size(&self) -> anyhow::Result<[f32; 2]> {
        let state = self.state.upgrade()?;
        let width = state._yn.get_layout_width().de_nan(0.0);
        let height = state._yn.get_layout_height().de_nan(0.0);
        Ok([width, height])
    }

    pub fn get_layout(&self) -> anyhow::Result<Layout> {
        let state = self.state.upgrade()?;
        Ok(state._yn.get_layout())
    }

    pub fn calculate_layout(&self, available_width: f32, available_height: f32, direction: Direction) -> anyhow::Result<()> {
        let mut state = self.state.upgrade()?;
        state._yn.calculate_layout(available_width, available_height, direction);
        Ok(())
    }

    pub fn calculate_shadow_layout(&self, available_width: f32, available_height: f32, direction: Direction) -> anyhow::Result<()> {
        let mut state = self.state.upgrade()?;
        if let Some(yn) = &mut state._shadow_yn {
            yn.calculate_layout(available_width, available_height, direction);
            state.shadow_layout_calculated = true;
        }
        Ok(())
    }
    
    pub fn is_shadow_layout_calculated(&self) -> anyhow::Result<bool> {
        let state = self.state.upgrade()?;
        Ok(state.shadow_layout_calculated)
    }
}