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