1pub mod area;
2pub mod content;
3pub mod flex;
4pub mod grid;
5pub mod image;
6pub mod portal;
7pub mod size;
8pub mod text;
9
10use crate::{
11 props::Props,
12 widget::{
13 WidgetId,
14 node::WidgetNode,
15 unit::{
16 area::{AreaBox, AreaBoxNode, AreaBoxNodePrefab},
17 content::{ContentBox, ContentBoxNode, ContentBoxNodePrefab},
18 flex::{FlexBox, FlexBoxNode, FlexBoxNodePrefab},
19 grid::{GridBox, GridBoxNode, GridBoxNodePrefab},
20 image::{ImageBox, ImageBoxNode, ImageBoxNodePrefab},
21 portal::{PortalBox, PortalBoxNode, PortalBoxNodePrefab},
22 size::{SizeBox, SizeBoxNode, SizeBoxNodePrefab},
23 text::{TextBox, TextBoxNode, TextBoxNodePrefab},
24 },
25 },
26};
27use serde::{Deserialize, Serialize};
28use std::convert::TryFrom;
29
30#[derive(Debug, Default, Clone, Serialize, Deserialize)]
31pub struct WidgetUnitInspectionNode {
32 #[serde(default)]
33 pub id: WidgetId,
34 #[serde(default)]
35 #[serde(skip_serializing_if = "Vec::is_empty")]
36 pub children: Vec<WidgetUnitInspectionNode>,
37}
38
39pub trait WidgetUnitData {
40 fn id(&self) -> &WidgetId;
41
42 fn get_children(&self) -> Vec<&WidgetUnit> {
43 vec![]
44 }
45}
46
47#[derive(Debug, Default, Clone, Serialize, Deserialize)]
48pub enum WidgetUnit {
49 #[default]
50 None,
51 AreaBox(AreaBox),
52 PortalBox(PortalBox),
53 ContentBox(ContentBox),
54 FlexBox(FlexBox),
55 GridBox(GridBox),
56 SizeBox(SizeBox),
57 ImageBox(ImageBox),
58 TextBox(TextBox),
59}
60
61impl WidgetUnit {
62 pub fn is_none(&self) -> bool {
63 matches!(self, Self::None)
64 }
65
66 pub fn is_some(&self) -> bool {
67 !matches!(self, Self::None)
68 }
69
70 pub fn as_data(&self) -> Option<&dyn WidgetUnitData> {
71 match self {
72 Self::None => None,
73 Self::AreaBox(v) => Some(v as &dyn WidgetUnitData),
74 Self::PortalBox(v) => Some(v as &dyn WidgetUnitData),
75 Self::ContentBox(v) => Some(v as &dyn WidgetUnitData),
76 Self::FlexBox(v) => Some(v as &dyn WidgetUnitData),
77 Self::GridBox(v) => Some(v as &dyn WidgetUnitData),
78 Self::SizeBox(v) => Some(v as &dyn WidgetUnitData),
79 Self::ImageBox(v) => Some(v as &dyn WidgetUnitData),
80 Self::TextBox(v) => Some(v as &dyn WidgetUnitData),
81 }
82 }
83
84 pub fn inspect(&self) -> Option<WidgetUnitInspectionNode> {
85 self.as_data().map(|data| WidgetUnitInspectionNode {
86 id: data.id().to_owned(),
87 children: data
88 .get_children()
89 .into_iter()
90 .filter_map(|child| child.inspect())
91 .collect::<Vec<_>>(),
92 })
93 }
94}
95
96impl TryFrom<WidgetUnitNode> for WidgetUnit {
97 type Error = ();
98
99 fn try_from(node: WidgetUnitNode) -> Result<Self, Self::Error> {
100 match node {
101 WidgetUnitNode::None => Ok(Self::None),
102 WidgetUnitNode::AreaBox(n) => Ok(WidgetUnit::AreaBox(AreaBox::try_from(n)?)),
103 WidgetUnitNode::PortalBox(n) => Ok(WidgetUnit::PortalBox(PortalBox::try_from(n)?)),
104 WidgetUnitNode::ContentBox(n) => Ok(WidgetUnit::ContentBox(ContentBox::try_from(n)?)),
105 WidgetUnitNode::FlexBox(n) => Ok(WidgetUnit::FlexBox(FlexBox::try_from(n)?)),
106 WidgetUnitNode::GridBox(n) => Ok(WidgetUnit::GridBox(GridBox::try_from(n)?)),
107 WidgetUnitNode::SizeBox(n) => Ok(WidgetUnit::SizeBox(SizeBox::try_from(n)?)),
108 WidgetUnitNode::ImageBox(n) => Ok(WidgetUnit::ImageBox(ImageBox::try_from(n)?)),
109 WidgetUnitNode::TextBox(n) => Ok(WidgetUnit::TextBox(TextBox::try_from(n)?)),
110 }
111 }
112}
113
114impl TryFrom<WidgetNode> for WidgetUnit {
115 type Error = ();
116
117 fn try_from(node: WidgetNode) -> Result<Self, Self::Error> {
118 match node {
119 WidgetNode::None | WidgetNode::Tuple(_) => Ok(Self::None),
120 WidgetNode::Component(_) => Err(()),
121 WidgetNode::Unit(u) => Self::try_from(u),
122 }
123 }
124}
125
126#[derive(Debug, Default, Clone)]
127pub enum WidgetUnitNode {
128 #[default]
129 None,
130 AreaBox(AreaBoxNode),
131 PortalBox(PortalBoxNode),
132 ContentBox(ContentBoxNode),
133 FlexBox(FlexBoxNode),
134 GridBox(GridBoxNode),
135 SizeBox(SizeBoxNode),
136 ImageBox(ImageBoxNode),
137 TextBox(TextBoxNode),
138}
139
140impl WidgetUnitNode {
141 pub fn is_none(&self) -> bool {
142 matches!(self, Self::None)
143 }
144
145 pub fn is_some(&self) -> bool {
146 !matches!(self, Self::None)
147 }
148
149 pub fn props(&self) -> Option<&Props> {
150 match self {
151 Self::None | Self::AreaBox(_) | Self::PortalBox(_) => None,
152 Self::ContentBox(v) => Some(&v.props),
153 Self::FlexBox(v) => Some(&v.props),
154 Self::GridBox(v) => Some(&v.props),
155 Self::SizeBox(v) => Some(&v.props),
156 Self::ImageBox(v) => Some(&v.props),
157 Self::TextBox(v) => Some(&v.props),
158 }
159 }
160
161 pub fn props_mut(&mut self) -> Option<&mut Props> {
162 match self {
163 Self::None | Self::AreaBox(_) | Self::PortalBox(_) => None,
164 Self::ContentBox(v) => Some(&mut v.props),
165 Self::FlexBox(v) => Some(&mut v.props),
166 Self::GridBox(v) => Some(&mut v.props),
167 Self::SizeBox(v) => Some(&mut v.props),
168 Self::ImageBox(v) => Some(&mut v.props),
169 Self::TextBox(v) => Some(&mut v.props),
170 }
171 }
172
173 pub fn remap_props<F>(&mut self, f: F)
174 where
175 F: FnMut(Props) -> Props,
176 {
177 match self {
178 Self::None | Self::AreaBox(_) | Self::PortalBox(_) => {}
179 Self::ContentBox(v) => v.remap_props(f),
180 Self::FlexBox(v) => v.remap_props(f),
181 Self::GridBox(v) => v.remap_props(f),
182 Self::SizeBox(v) => v.remap_props(f),
183 Self::ImageBox(v) => v.remap_props(f),
184 Self::TextBox(v) => v.remap_props(f),
185 }
186 }
187}
188
189impl TryFrom<WidgetNode> for WidgetUnitNode {
190 type Error = ();
191
192 fn try_from(node: WidgetNode) -> Result<Self, Self::Error> {
193 if let WidgetNode::Unit(v) = node {
194 Ok(v)
195 } else {
196 Err(())
197 }
198 }
199}
200
201impl From<()> for WidgetUnitNode {
202 fn from(_: ()) -> Self {
203 Self::None
204 }
205}
206
207macro_rules! implement_from_unit {
208 { $( $type_name:ident => $variant_name:ident ),+ $(,)? } => {
209 $(
210 impl From<$type_name> for WidgetUnitNode {
211 fn from(unit: $type_name) -> Self {
212 Self::$variant_name(unit)
213 }
214 }
215 )+
216 };
217}
218
219implement_from_unit! {
220 AreaBoxNode => AreaBox,
221 PortalBoxNode => PortalBox,
222 ContentBoxNode => ContentBox,
223 FlexBoxNode => FlexBox,
224 GridBoxNode => GridBox,
225 SizeBoxNode => SizeBox,
226 ImageBoxNode => ImageBox,
227 TextBoxNode => TextBox,
228}
229
230#[derive(Debug, Default, Clone, Serialize, Deserialize)]
231pub(crate) enum WidgetUnitNodePrefab {
232 #[default]
233 None,
234 AreaBox(AreaBoxNodePrefab),
235 PortalBox(PortalBoxNodePrefab),
236 ContentBox(ContentBoxNodePrefab),
237 FlexBox(FlexBoxNodePrefab),
238 GridBox(GridBoxNodePrefab),
239 SizeBox(SizeBoxNodePrefab),
240 ImageBox(ImageBoxNodePrefab),
241 TextBox(TextBoxNodePrefab),
242}