raui_material/component/containers/
paper.rs1use 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}