raui_material/component/interactive/
button_paper.rs1use crate::{
2 component::containers::paper::PaperProps,
3 theme::{ThemeColor, ThemeProps, ThemeVariant, ThemedImageMaterial, ThemedWidgetProps},
4};
5use raui_core::{
6 PropsData, Scalar, make_widget,
7 props::Props,
8 unpack_named_slots,
9 widget::{
10 component::{
11 WidgetComponent,
12 containers::content_box::content_box,
13 image_box::{ImageBoxProps, image_box},
14 interactive::button::{ButtonProps, button},
15 },
16 context::WidgetContext,
17 node::WidgetNode,
18 unit::{
19 content::ContentBoxItemLayout,
20 image::{ImageBoxColor, ImageBoxImageScaling, ImageBoxMaterial},
21 },
22 },
23};
24use serde::{Deserialize, Serialize};
25
26#[derive(PropsData, Debug, Default, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
27#[props_data(raui_core::props::PropsData)]
28#[prefab(raui_core::Prefab)]
29pub enum ButtonPaperOverrideStyle {
30 #[default]
31 None,
32 Default,
33 Selected,
34 Triggered,
35}
36
37fn button_paper_content(context: WidgetContext) -> WidgetNode {
38 let WidgetContext {
39 key,
40 props,
41 shared_props,
42 named_slots,
43 ..
44 } = context;
45 unpack_named_slots!(named_slots => content);
46
47 let mut button_props = props.read_cloned_or_default::<ButtonProps>();
48 let paper_props = props.read_cloned_or_default::<PaperProps>();
49 let themed_props = props.read_cloned_or_default::<ThemedWidgetProps>();
50 let override_style = props.read_cloned_or_default::<ButtonPaperOverrideStyle>();
51
52 if override_style != ButtonPaperOverrideStyle::None {
53 button_props.selected = override_style == ButtonPaperOverrideStyle::Selected;
54 button_props.trigger = override_style == ButtonPaperOverrideStyle::Triggered;
55 button_props.context = false;
56 }
57
58 let items = match themed_props.variant {
59 ThemeVariant::ContentOnly => vec![content],
60 ThemeVariant::Filled => {
61 let button_background = shared_props.map_or_default::<ThemeProps, _, _>(|props| {
62 if button_props.trigger || button_props.context {
63 props
64 .button_backgrounds
65 .get(&paper_props.variant)
66 .cloned()
67 .unwrap_or_default()
68 .trigger
69 } else if button_props.selected {
70 props
71 .button_backgrounds
72 .get(&paper_props.variant)
73 .cloned()
74 .unwrap_or_default()
75 .selected
76 } else {
77 props
78 .button_backgrounds
79 .get(&paper_props.variant)
80 .cloned()
81 .unwrap_or_default()
82 .default
83 }
84 });
85 let button_colors = shared_props
86 .map_or_default::<ThemeProps, _, _>(|props| props.active_colors.clone());
87 let image = match button_background {
88 ThemedImageMaterial::Color => {
89 let color = match themed_props.color {
90 ThemeColor::Default => button_colors.main.default.main,
91 ThemeColor::Primary => button_colors.main.primary.main,
92 ThemeColor::Secondary => button_colors.main.secondary.main,
93 };
94 ImageBoxProps {
95 material: ImageBoxMaterial::Color(ImageBoxColor {
96 color,
97 ..Default::default()
98 }),
99 ..Default::default()
100 }
101 }
102 ThemedImageMaterial::Image(material) => ImageBoxProps {
103 material: ImageBoxMaterial::Image(material),
104 ..Default::default()
105 },
106 ThemedImageMaterial::Procedural(material) => ImageBoxProps {
107 material: ImageBoxMaterial::Procedural(material),
108 ..Default::default()
109 },
110 };
111 let props = Props::new(ContentBoxItemLayout {
112 depth: Scalar::NEG_INFINITY,
113 ..Default::default()
114 })
115 .with(image);
116 let background = make_widget!(image_box)
117 .key("background")
118 .merge_props(props)
119 .into();
120 if let Some(frame) = paper_props.frame {
121 let color = match themed_props.color {
122 ThemeColor::Default => button_colors.main.default.dark,
123 ThemeColor::Primary => button_colors.main.primary.dark,
124 ThemeColor::Secondary => button_colors.main.secondary.dark,
125 };
126 let props = Props::new(ContentBoxItemLayout {
127 depth: Scalar::NEG_INFINITY,
128 ..Default::default()
129 })
130 .with(ImageBoxProps {
131 material: ImageBoxMaterial::Color(ImageBoxColor {
132 color,
133 scaling: ImageBoxImageScaling::Frame(frame),
134 }),
135 ..Default::default()
136 });
137 let frame = make_widget!(image_box)
138 .key("frame")
139 .merge_props(props)
140 .into();
141 vec![background, frame, content]
142 } else {
143 vec![background, content]
144 }
145 }
146 ThemeVariant::Outline => {
147 if let Some(frame) = paper_props.frame {
148 let button_colors = shared_props
149 .map_or_default::<ThemeProps, _, _>(|props| props.active_colors.clone());
150 let color = match themed_props.color {
151 ThemeColor::Default => button_colors.main.default.dark,
152 ThemeColor::Primary => button_colors.main.primary.dark,
153 ThemeColor::Secondary => button_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 vec![frame, content]
171 } else {
172 vec![content]
173 }
174 }
175 };
176
177 make_widget!(content_box)
178 .key(key)
179 .merge_props(props.clone())
180 .listed_slots(items)
181 .into()
182}
183
184pub fn button_paper(context: WidgetContext) -> WidgetNode {
185 button_paper_impl(make_widget!(button), context)
186}
187
188pub fn button_paper_impl(component: WidgetComponent, context: WidgetContext) -> WidgetNode {
189 let WidgetContext {
190 idref,
191 key,
192 props,
193 named_slots,
194 ..
195 } = context;
196 unpack_named_slots!(named_slots => content);
197
198 component
199 .key(key)
200 .maybe_idref(idref.cloned())
201 .merge_props(props.clone())
202 .named_slot(
203 "content",
204 make_widget!(button_paper_content)
205 .key("content")
206 .merge_props(props.clone())
207 .named_slot("content", content),
208 )
209 .into()
210}