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