raui_core/widget/unit/
content.rs

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, Vec2},
9    },
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/// Allows customizing how an item in a [`content_box`] is laid out
72///
73/// [`content_box`]: crate::widget::component::containers::content_box::content_box
74#[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    /// The margins to put on each side of the item
81    #[serde(default)]
82    pub margin: Rect,
83    /// Tells in percentage, where is the center of mass of the widget, relative to it's box size
84    #[serde(default)]
85    pub align: Vec2,
86    /// The amount to offset the item from where it would otherwise be laid out
87    #[serde(default)]
88    pub offset: Vec2,
89    /// The "Z" depth of the item
90    #[serde(default)]
91    pub depth: Scalar,
92    /// Set of constraints that tell if and how to keep item in container bounds
93    #[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, Clone, Copy, Serialize, Deserialize)]
148pub struct ContentBoxContentReposition {
149    #[serde(default)]
150    pub offset: Vec2,
151    #[serde(default = "ContentBoxContentReposition::default_scale")]
152    pub scale: Vec2,
153}
154
155impl Default for ContentBoxContentReposition {
156    fn default() -> Self {
157        Self {
158            offset: Default::default(),
159            scale: Self::default_scale(),
160        }
161    }
162}
163
164impl ContentBoxContentReposition {
165    fn default_scale() -> Vec2 {
166        1.0.into()
167    }
168}
169
170#[derive(Debug, Default, Clone, Serialize, Deserialize)]
171pub struct ContentBox {
172    #[serde(default)]
173    pub id: WidgetId,
174    #[serde(default)]
175    #[serde(skip_serializing_if = "Vec::is_empty")]
176    pub items: Vec<ContentBoxItem>,
177    #[serde(default)]
178    pub clipping: bool,
179    #[serde(default)]
180    pub content_reposition: ContentBoxContentReposition,
181    #[serde(default)]
182    pub transform: Transform,
183}
184
185impl WidgetUnitData for ContentBox {
186    fn id(&self) -> &WidgetId {
187        &self.id
188    }
189
190    fn get_children(&self) -> Vec<&WidgetUnit> {
191        self.items.iter().map(|item| &item.slot).collect()
192    }
193}
194
195impl TryFrom<ContentBoxNode> for ContentBox {
196    type Error = ();
197
198    fn try_from(node: ContentBoxNode) -> Result<Self, Self::Error> {
199        let ContentBoxNode {
200            id,
201            items,
202            clipping,
203            content_reposition,
204            transform,
205            ..
206        } = node;
207        let items = items
208            .into_iter()
209            .map(ContentBoxItem::try_from)
210            .collect::<Result<_, _>>()?;
211        Ok(Self {
212            id,
213            items,
214            clipping,
215            content_reposition,
216            transform,
217        })
218    }
219}
220
221#[derive(Debug, Default, Clone)]
222pub struct ContentBoxNode {
223    pub id: WidgetId,
224    pub props: Props,
225    pub items: Vec<ContentBoxItemNode>,
226    pub clipping: bool,
227    pub content_reposition: ContentBoxContentReposition,
228    pub transform: Transform,
229}
230
231impl ContentBoxNode {
232    pub fn remap_props<F>(&mut self, mut f: F)
233    where
234        F: FnMut(Props) -> Props,
235    {
236        let props = std::mem::take(&mut self.props);
237        self.props = (f)(props);
238    }
239}
240
241impl From<ContentBoxNode> for WidgetNode {
242    fn from(data: ContentBoxNode) -> Self {
243        Self::Unit(data.into())
244    }
245}
246
247#[derive(Debug, Default, Clone, Serialize, Deserialize)]
248pub(crate) struct ContentBoxNodePrefab {
249    #[serde(default)]
250    pub id: WidgetId,
251    #[serde(default)]
252    pub props: PrefabValue,
253    #[serde(default)]
254    #[serde(skip_serializing_if = "Vec::is_empty")]
255    pub items: Vec<ContentBoxItemNodePrefab>,
256    #[serde(default)]
257    pub clipping: bool,
258    #[serde(default)]
259    pub content_reposition: ContentBoxContentReposition,
260    #[serde(default)]
261    pub transform: Transform,
262}
263
264#[derive(Debug, Default, Clone, Serialize, Deserialize)]
265pub(crate) struct ContentBoxItemNodePrefab {
266    #[serde(default)]
267    pub slot: WidgetNodePrefab,
268    #[serde(default)]
269    pub layout: ContentBoxItemLayout,
270}