1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
pub mod content;
pub mod flex;
pub mod grid;
pub mod image;
pub mod size;
pub mod text;

use crate::widget::{
    node::WidgetNode,
    unit::{
        content::ContentBox, flex::FlexBox, grid::GridBox, image::ImageBox, size::SizeBox,
        text::TextBox,
    },
    WidgetId,
};
use serde::{Deserialize, Serialize};
use std::convert::TryFrom;

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct WidgetUnitInspectionNode {
    pub id: WidgetId,
    pub children: Vec<WidgetUnitInspectionNode>,
}

pub trait WidgetUnitData {
    fn id(&self) -> &WidgetId;

    fn get_children<'a>(&'a self) -> Vec<&'a WidgetUnit> {
        vec![]
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum WidgetUnit {
    None,
    ContentBox(ContentBox),
    FlexBox(FlexBox),
    GridBox(GridBox),
    SizeBox(SizeBox),
    ImageBox(ImageBox),
    TextBox(TextBox),
}

impl Default for WidgetUnit {
    fn default() -> Self {
        Self::None
    }
}

impl WidgetUnit {
    pub fn is_none(&self) -> bool {
        match self {
            Self::None => true,
            _ => false,
        }
    }

    pub fn is_some(&self) -> bool {
        match self {
            Self::None => false,
            _ => true,
        }
    }

    pub fn as_data(&self) -> Option<&dyn WidgetUnitData> {
        match self {
            Self::None => None,
            Self::ContentBox(v) => Some(v as &dyn WidgetUnitData),
            Self::FlexBox(v) => Some(v as &dyn WidgetUnitData),
            Self::GridBox(v) => Some(v as &dyn WidgetUnitData),
            Self::SizeBox(v) => Some(v as &dyn WidgetUnitData),
            Self::ImageBox(v) => Some(v as &dyn WidgetUnitData),
            Self::TextBox(v) => Some(v as &dyn WidgetUnitData),
        }
    }

    pub fn inspect(&self) -> Option<WidgetUnitInspectionNode> {
        if let Some(data) = self.as_data() {
            Some(WidgetUnitInspectionNode {
                id: data.id().to_owned(),
                children: data
                    .get_children()
                    .into_iter()
                    .filter_map(|child| child.inspect())
                    .collect::<Vec<_>>(),
            })
        } else {
            None
        }
    }
}

impl TryFrom<WidgetNode> for WidgetUnit {
    type Error = ();

    fn try_from(node: WidgetNode) -> Result<Self, Self::Error> {
        if let WidgetNode::Unit(v) = node {
            Ok(v)
        } else {
            Err(())
        }
    }
}

impl From<()> for WidgetUnit {
    fn from(_: ()) -> Self {
        Self::None
    }
}

macro_rules! implement_from_unit {
    { $( $type_name:ident ),+ $(,)? } => {
        $(
            impl From<$type_name> for WidgetUnit {
                fn from(unit: $type_name) -> Self {
                    Self::$type_name(unit)
                }
            }
        )+
    };
}

implement_from_unit! {
    ContentBox,
    FlexBox,
    GridBox,
    SizeBox,
    ImageBox,
    TextBox,
}