1use crate::{
2 PrefabValue, PropsData, Scalar,
3 props::Props,
4 widget::{
5 WidgetId,
6 node::{WidgetNode, WidgetNodePrefab},
7 unit::{WidgetUnit, WidgetUnitData},
8 utils::{Rect, Transform},
9 },
10};
11use serde::{Deserialize, Serialize};
12use std::convert::TryFrom;
13
14#[derive(PropsData, Debug, Clone, Serialize, Deserialize)]
15#[props_data(crate::props::PropsData)]
16#[prefab(crate::Prefab)]
17pub struct FlexBoxItemLayout {
18 #[serde(default)]
19 #[serde(skip_serializing_if = "Option::is_none")]
20 pub basis: Option<Scalar>,
21 #[serde(default = "FlexBoxItemLayout::default_fill")]
22 pub fill: Scalar,
23 #[serde(default = "FlexBoxItemLayout::default_grow")]
24 pub grow: Scalar,
25 #[serde(default = "FlexBoxItemLayout::default_shrink")]
26 pub shrink: Scalar,
27 #[serde(default)]
28 pub margin: Rect,
29 #[serde(default)]
30 pub align: Scalar,
31}
32
33impl FlexBoxItemLayout {
34 fn default_fill() -> Scalar {
35 1.0
36 }
37
38 fn default_grow() -> Scalar {
39 1.0
40 }
41
42 fn default_shrink() -> Scalar {
43 1.0
44 }
45
46 pub fn cleared() -> Self {
47 Self {
48 fill: 0.0,
49 grow: 0.0,
50 shrink: 0.0,
51 ..Default::default()
52 }
53 }
54}
55
56impl Default for FlexBoxItemLayout {
57 fn default() -> Self {
58 Self {
59 basis: None,
60 fill: Self::default_fill(),
61 grow: Self::default_grow(),
62 shrink: Self::default_shrink(),
63 margin: Default::default(),
64 align: 0.0,
65 }
66 }
67}
68
69#[derive(Debug, Default, Clone, Serialize, Deserialize)]
70pub struct FlexBoxItem {
71 #[serde(default)]
72 pub slot: WidgetUnit,
73 #[serde(default)]
74 pub layout: FlexBoxItemLayout,
75}
76
77impl TryFrom<FlexBoxItemNode> for FlexBoxItem {
78 type Error = ();
79
80 fn try_from(node: FlexBoxItemNode) -> Result<Self, Self::Error> {
81 let FlexBoxItemNode { slot, layout } = node;
82 Ok(Self {
83 slot: WidgetUnit::try_from(slot)?,
84 layout,
85 })
86 }
87}
88
89#[derive(Debug, Default, Clone)]
90pub struct FlexBoxItemNode {
91 pub slot: WidgetNode,
92 pub layout: FlexBoxItemLayout,
93}
94
95#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
96pub enum FlexBoxDirection {
97 #[default]
98 HorizontalLeftToRight,
99 HorizontalRightToLeft,
100 VerticalTopToBottom,
101 VerticalBottomToTop,
102}
103
104impl FlexBoxDirection {
105 pub fn is_horizontal(&self) -> bool {
106 *self == Self::HorizontalLeftToRight || *self == Self::HorizontalRightToLeft
107 }
108
109 pub fn is_vertical(&self) -> bool {
110 *self == Self::VerticalTopToBottom || *self == Self::VerticalBottomToTop
111 }
112
113 pub fn is_order_ascending(&self) -> bool {
114 *self == Self::HorizontalLeftToRight || *self == Self::VerticalTopToBottom
115 }
116
117 pub fn is_order_descending(&self) -> bool {
118 *self == Self::HorizontalRightToLeft || *self == Self::VerticalBottomToTop
119 }
120}
121
122#[derive(Debug, Default, Clone, Serialize, Deserialize)]
123pub struct FlexBox {
124 #[serde(default)]
125 pub id: WidgetId,
126 #[serde(default)]
127 #[serde(skip_serializing_if = "Vec::is_empty")]
128 pub items: Vec<FlexBoxItem>,
129 #[serde(default)]
130 pub direction: FlexBoxDirection,
131 #[serde(default)]
132 pub separation: Scalar,
133 #[serde(default)]
134 pub wrap: bool,
135 #[serde(default)]
136 pub transform: Transform,
137}
138
139impl WidgetUnitData for FlexBox {
140 fn id(&self) -> &WidgetId {
141 &self.id
142 }
143
144 fn get_children(&self) -> Vec<&WidgetUnit> {
145 self.items.iter().map(|item| &item.slot).collect()
146 }
147}
148
149impl TryFrom<FlexBoxNode> for FlexBox {
150 type Error = ();
151
152 fn try_from(node: FlexBoxNode) -> Result<Self, Self::Error> {
153 let FlexBoxNode {
154 id,
155 items,
156 direction,
157 separation,
158 wrap,
159 transform,
160 ..
161 } = node;
162 let items = items
163 .into_iter()
164 .map(FlexBoxItem::try_from)
165 .collect::<Result<_, _>>()?;
166 Ok(Self {
167 id,
168 items,
169 direction,
170 separation,
171 wrap,
172 transform,
173 })
174 }
175}
176
177#[derive(Debug, Default, Clone)]
178pub struct FlexBoxNode {
179 pub id: WidgetId,
180 pub props: Props,
181 pub items: Vec<FlexBoxItemNode>,
182 pub direction: FlexBoxDirection,
183 pub separation: Scalar,
184 pub wrap: bool,
185 pub transform: Transform,
186}
187
188impl FlexBoxNode {
189 pub fn remap_props<F>(&mut self, mut f: F)
190 where
191 F: FnMut(Props) -> Props,
192 {
193 let props = std::mem::take(&mut self.props);
194 self.props = (f)(props);
195 }
196}
197
198impl From<FlexBoxNode> for WidgetNode {
199 fn from(data: FlexBoxNode) -> Self {
200 Self::Unit(data.into())
201 }
202}
203
204#[derive(Debug, Default, Clone, Serialize, Deserialize)]
205pub(crate) struct FlexBoxNodePrefab {
206 #[serde(default)]
207 pub id: WidgetId,
208 #[serde(default)]
209 pub props: PrefabValue,
210 #[serde(default)]
211 #[serde(skip_serializing_if = "Vec::is_empty")]
212 pub items: Vec<FlexBoxItemNodePrefab>,
213 #[serde(default)]
214 pub direction: FlexBoxDirection,
215 #[serde(default)]
216 pub separation: Scalar,
217 #[serde(default)]
218 pub wrap: bool,
219 #[serde(default)]
220 pub transform: Transform,
221}
222
223#[derive(Debug, Default, Clone, Serialize, Deserialize)]
224pub(crate) struct FlexBoxItemNodePrefab {
225 #[serde(default)]
226 pub slot: WidgetNodePrefab,
227 #[serde(default)]
228 pub layout: FlexBoxItemLayout,
229}