raui_material/component/containers/
paper.rs

1use crate::theme::{ThemeColor, ThemeProps, ThemeVariant, ThemedImageMaterial, ThemedWidgetProps};
2use raui_core::{
3    PropsData, Scalar, make_widget,
4    props::Props,
5    widget::{
6        component::{
7            WidgetComponent,
8            containers::content_box::{content_box, nav_content_box},
9            image_box::{ImageBoxProps, image_box},
10        },
11        context::WidgetContext,
12        node::WidgetNode,
13        unit::{
14            content::ContentBoxItemLayout,
15            image::{ImageBoxColor, ImageBoxFrame, ImageBoxImageScaling, ImageBoxMaterial},
16        },
17    },
18};
19use serde::{Deserialize, Serialize};
20
21#[derive(PropsData, Debug, Default, Clone, Serialize, Deserialize)]
22#[props_data(raui_core::props::PropsData)]
23#[prefab(raui_core::Prefab)]
24pub struct PaperProps {
25    #[serde(default)]
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub frame: Option<ImageBoxFrame>,
28    #[serde(default)]
29    pub variant: String,
30}
31
32#[derive(PropsData, Debug, Default, Clone, Serialize, Deserialize)]
33#[props_data(raui_core::props::PropsData)]
34#[prefab(raui_core::Prefab)]
35pub struct PaperContentLayoutProps(pub ContentBoxItemLayout);
36
37pub fn nav_paper(context: WidgetContext) -> WidgetNode {
38    paper_impl(make_widget!(nav_content_box), context)
39}
40
41pub fn paper(context: WidgetContext) -> WidgetNode {
42    paper_impl(make_widget!(content_box), context)
43}
44
45pub fn paper_impl(component: WidgetComponent, context: WidgetContext) -> WidgetNode {
46    let WidgetContext {
47        idref,
48        key,
49        props,
50        shared_props,
51        listed_slots,
52        ..
53    } = context;
54
55    let paper_props = props.read_cloned_or_default::<PaperProps>();
56    let themed_props = props.read_cloned_or_default::<ThemedWidgetProps>();
57    let listed_slots = listed_slots
58        .into_iter()
59        .map(|mut item| {
60            item.remap_props(|mut props| {
61                if let Ok(PaperContentLayoutProps(layout)) = props.consume_unwrap_cloned() {
62                    props.write(layout);
63                }
64                props
65            });
66            item
67        })
68        .collect::<Vec<_>>();
69
70    let items = match themed_props.variant {
71        ThemeVariant::ContentOnly => listed_slots,
72        ThemeVariant::Filled => {
73            let content_background = shared_props.map_or_default::<ThemeProps, _, _>(|props| {
74                props
75                    .content_backgrounds
76                    .get(&paper_props.variant)
77                    .cloned()
78                    .unwrap_or_default()
79            });
80            let background_colors = shared_props
81                .map_or_default::<ThemeProps, _, _>(|props| props.background_colors.clone());
82            let image = match content_background {
83                ThemedImageMaterial::Color => {
84                    let color = match themed_props.color {
85                        ThemeColor::Default => background_colors.main.default.main,
86                        ThemeColor::Primary => background_colors.main.primary.main,
87                        ThemeColor::Secondary => background_colors.main.secondary.main,
88                    };
89                    ImageBoxProps {
90                        material: ImageBoxMaterial::Color(ImageBoxColor {
91                            color,
92                            ..Default::default()
93                        }),
94                        ..Default::default()
95                    }
96                }
97                ThemedImageMaterial::Image(material) => ImageBoxProps {
98                    material: ImageBoxMaterial::Image(material),
99                    ..Default::default()
100                },
101                ThemedImageMaterial::Procedural(material) => ImageBoxProps {
102                    material: ImageBoxMaterial::Procedural(material),
103                    ..Default::default()
104                },
105            };
106            let props = Props::new(ContentBoxItemLayout {
107                depth: Scalar::NEG_INFINITY,
108                ..Default::default()
109            })
110            .with(image);
111            let background = make_widget!(image_box)
112                .key("background")
113                .merge_props(props)
114                .into();
115            if let Some(frame) = paper_props.frame {
116                let color = match themed_props.color {
117                    ThemeColor::Default => background_colors.main.default.dark,
118                    ThemeColor::Primary => background_colors.main.primary.dark,
119                    ThemeColor::Secondary => background_colors.main.secondary.dark,
120                };
121                let props = Props::new(ContentBoxItemLayout {
122                    depth: Scalar::NEG_INFINITY,
123                    ..Default::default()
124                })
125                .with(ImageBoxProps {
126                    material: ImageBoxMaterial::Color(ImageBoxColor {
127                        color,
128                        scaling: ImageBoxImageScaling::Frame(frame),
129                    }),
130                    ..Default::default()
131                });
132                let frame = make_widget!(image_box)
133                    .key("frame")
134                    .merge_props(props)
135                    .into();
136                std::iter::once(background)
137                    .chain(std::iter::once(frame))
138                    .chain(listed_slots)
139                    .collect::<Vec<_>>()
140            } else {
141                std::iter::once(background)
142                    .chain(listed_slots)
143                    .collect::<Vec<_>>()
144            }
145        }
146        ThemeVariant::Outline => {
147            if let Some(frame) = paper_props.frame {
148                let background_colors = shared_props
149                    .map_or_default::<ThemeProps, _, _>(|props| props.background_colors.clone());
150                let color = match themed_props.color {
151                    ThemeColor::Default => background_colors.main.default.dark,
152                    ThemeColor::Primary => background_colors.main.primary.dark,
153                    ThemeColor::Secondary => background_colors.main.secondary.dark,
154                };
155                let props = Props::new(ContentBoxItemLayout {
156                    depth: Scalar::NEG_INFINITY,
157                    ..Default::default()
158                })
159                .with(ImageBoxProps {
160                    material: ImageBoxMaterial::Color(ImageBoxColor {
161                        color,
162                        scaling: ImageBoxImageScaling::Frame(frame),
163                    }),
164                    ..Default::default()
165                });
166                let frame = make_widget!(image_box)
167                    .key("frame")
168                    .merge_props(props)
169                    .into();
170                std::iter::once(frame)
171                    .chain(listed_slots)
172                    .collect::<Vec<_>>()
173            } else {
174                listed_slots
175            }
176        }
177    };
178
179    component
180        .key(key)
181        .maybe_idref(idref.cloned())
182        .merge_props(props.clone())
183        .listed_slots(items)
184        .into()
185}