raui_core/widget/unit/
content.rs

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/// 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, 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}