1use super::{inspector_metadata, GraphicsLayer, Modifier};
2use crate::modifier_nodes::{GraphicsLayerElement, LazyGraphicsLayerElement};
3use cranpose_ui_graphics::{
4 gradient_cut_mask_effect, gradient_fade_dst_out_effect, rounded_alpha_mask_effect, BlendMode,
5 Color, ColorFilter, CompositingStrategy, Dp, GradientCutMaskSpec, GradientFadeMaskSpec,
6 LayerShape, RenderEffect, RoundedCornerShape, RuntimeShader, TransformOrigin,
7};
8use std::rc::Rc;
9
10fn backdrop_blur_layer(radius: Dp, shape: LayerShape) -> GraphicsLayer {
11 let radius_px = radius
12 .to_px(crate::render_state::current_density())
13 .max(0.0);
14 GraphicsLayer {
15 backdrop_effect: (radius_px > 0.0).then(|| RenderEffect::blur(radius_px)),
16 shape,
17 clip: true,
18 ..Default::default()
19 }
20}
21
22impl Modifier {
23 pub fn graphics_layer(self, layer: impl Fn() -> GraphicsLayer + 'static) -> Self {
31 let modifier = Self::with_element(LazyGraphicsLayerElement::new(Rc::new(layer)))
32 .with_inspector_metadata(inspector_metadata("graphicsLayer", |info| {
33 info.add_property("lazy", "true");
34 }));
35 self.then(modifier)
36 }
37
38 pub fn graphics_layer_value(self, layer: GraphicsLayer) -> Self {
43 let inspector_values = layer.clone();
44 let modifier = Self::with_element(GraphicsLayerElement::new(layer))
45 .with_inspector_metadata(inspector_metadata("graphicsLayer", move |info| {
46 info.add_property("alpha", inspector_values.alpha.to_string());
47 info.add_property("scale", inspector_values.scale.to_string());
48 info.add_property("scaleX", inspector_values.scale_x.to_string());
49 info.add_property("scaleY", inspector_values.scale_y.to_string());
50 info.add_property("rotationX", inspector_values.rotation_x.to_string());
51 info.add_property("rotationY", inspector_values.rotation_y.to_string());
52 info.add_property("rotationZ", inspector_values.rotation_z.to_string());
53 info.add_property(
54 "cameraDistance",
55 inspector_values.camera_distance.to_string(),
56 );
57 info.add_property(
58 "transformOrigin",
59 format!(
60 "{},{}",
61 inspector_values.transform_origin.pivot_fraction_x,
62 inspector_values.transform_origin.pivot_fraction_y
63 ),
64 );
65 info.add_property("translationX", inspector_values.translation_x.to_string());
66 info.add_property("translationY", inspector_values.translation_y.to_string());
67 info.add_property(
68 "shadowElevation",
69 inspector_values.shadow_elevation.to_string(),
70 );
71 info.add_property("shape", format!("{:?}", inspector_values.shape));
72 info.add_property("clip", inspector_values.clip.to_string());
73 info.add_property(
74 "ambientShadowColor",
75 format!("{:?}", inspector_values.ambient_shadow_color),
76 );
77 info.add_property(
78 "spotShadowColor",
79 format!("{:?}", inspector_values.spot_shadow_color),
80 );
81 info.add_property(
82 "compositingStrategy",
83 format!("{:?}", inspector_values.compositing_strategy),
84 );
85 info.add_property("blendMode", format!("{:?}", inspector_values.blend_mode));
86 if let Some(filter) = inspector_values.color_filter {
87 info.add_property("colorFilter", format!("{filter:?}"));
88 }
89 }));
90 self.then(modifier)
91 }
92
93 #[allow(clippy::too_many_arguments)]
98 pub fn graphics_layer_params(
99 self,
100 scale_x: f32,
101 scale_y: f32,
102 alpha: f32,
103 translation_x: f32,
104 translation_y: f32,
105 shadow_elevation: f32,
106 rotation_x: f32,
107 rotation_y: f32,
108 rotation_z: f32,
109 camera_distance: f32,
110 transform_origin: TransformOrigin,
111 shape: LayerShape,
112 clip: bool,
113 render_effect: Option<RenderEffect>,
114 ambient_shadow_color: Color,
115 spot_shadow_color: Color,
116 compositing_strategy: CompositingStrategy,
117 blend_mode: BlendMode,
118 color_filter: Option<ColorFilter>,
119 ) -> Self {
120 self.graphics_layer_value(GraphicsLayer {
121 alpha,
122 scale: 1.0,
123 scale_x,
124 scale_y,
125 rotation_x,
126 rotation_y,
127 rotation_z,
128 camera_distance,
129 transform_origin,
130 translation_x,
131 translation_y,
132 shadow_elevation,
133 ambient_shadow_color,
134 spot_shadow_color,
135 shape,
136 clip,
137 compositing_strategy,
138 blend_mode,
139 color_filter,
140 render_effect,
141 backdrop_effect: None,
142 })
143 }
144
145 pub fn graphics_layer_block(self, configure: impl Fn(&mut GraphicsLayer) + 'static) -> Self {
150 self.graphics_layer(move || {
151 let mut layer = GraphicsLayer::default();
152 configure(&mut layer);
153 layer
154 })
155 }
156
157 pub fn shadow(self, elevation: f32) -> Self {
163 self.shadow_with(
164 elevation,
165 LayerShape::Rectangle,
166 elevation > 0.0,
167 Color::BLACK,
168 Color::BLACK,
169 )
170 }
171
172 pub fn shadow_with(
174 self,
175 elevation: f32,
176 shape: LayerShape,
177 clip: bool,
178 ambient_color: Color,
179 spot_color: Color,
180 ) -> Self {
181 let clamped_elevation = elevation.max(0.0);
182 if clamped_elevation == 0.0 && !clip {
183 return self;
184 }
185
186 self.graphics_layer_value(GraphicsLayer {
187 shadow_elevation: clamped_elevation,
188 ambient_shadow_color: ambient_color,
189 spot_shadow_color: spot_color,
190 shape,
191 clip,
192 ..Default::default()
193 })
194 }
195
196 pub fn backdrop_effect(self, effect: RenderEffect) -> Self {
198 let layer = GraphicsLayer {
199 backdrop_effect: Some(effect),
200 ..Default::default()
201 };
202 let modifier = Self::with_element(GraphicsLayerElement::new(layer))
203 .with_inspector_metadata(inspector_metadata("backdropEffect", |info| {
204 info.add_property("enabled", "true");
205 }));
206 self.then(modifier)
207 }
208
209 pub fn backdrop_blur(self, radius: Dp) -> Self {
214 if radius.0 <= 0.0 {
215 return self.clip_to_bounds();
216 }
217
218 let modifier = Self::with_element(LazyGraphicsLayerElement::new(Rc::new(move || {
219 backdrop_blur_layer(radius, LayerShape::Rectangle)
220 })))
221 .with_inspector_metadata(inspector_metadata("backdropBlur", move |info| {
222 info.add_property("radius", radius.0.to_string());
223 }));
224 self.then(modifier)
225 }
226
227 pub fn glass_material(self, material: GlassMaterial) -> Self {
229 let blur_radius = material.blur_radius;
230 let shape = material.shape;
231 let modifier = Self::with_element(LazyGraphicsLayerElement::new(Rc::new(move || {
232 backdrop_blur_layer(blur_radius, LayerShape::Rounded(shape))
233 })))
234 .with_inspector_metadata(inspector_metadata("glassMaterial", move |info| {
235 info.add_property("blurRadius", blur_radius.0.to_string());
236 info.add_property("shape", format!("{shape:?}"));
237 }));
238
239 self.then(modifier)
240 .rounded_corner_shape(material.shape)
241 .background(material.tint)
242 }
243
244 pub fn shader_background(self, shader: RuntimeShader) -> Self {
246 self.backdrop_effect(RenderEffect::runtime_shader(shader))
247 }
248
249 pub fn color_filter(self, filter: ColorFilter) -> Self {
253 let layer = GraphicsLayer {
254 color_filter: Some(filter),
255 ..Default::default()
256 };
257 let modifier = Self::with_element(GraphicsLayerElement::new(layer))
258 .with_inspector_metadata(inspector_metadata("colorFilter", |info| {
259 info.add_property("enabled", "true");
260 }));
261 self.then(modifier)
262 }
263
264 pub fn tint(self, tint: Color) -> Self {
266 self.color_filter(ColorFilter::tint(tint))
267 }
268
269 pub fn compositing_strategy(self, strategy: CompositingStrategy) -> Self {
271 self.graphics_layer_value(GraphicsLayer {
272 compositing_strategy: strategy,
273 ..Default::default()
274 })
275 }
276
277 pub fn layer_blend_mode(self, blend_mode: BlendMode) -> Self {
282 self.graphics_layer_value(GraphicsLayer {
283 blend_mode,
284 ..Default::default()
285 })
286 }
287
288 pub fn gradient_cut_mask(
292 self,
293 area_width: f32,
294 area_height: f32,
295 spec: GradientCutMaskSpec,
296 ) -> Self {
297 let layer = GraphicsLayer {
298 render_effect: Some(gradient_cut_mask_effect(&spec, area_width, area_height)),
299 ..Default::default()
300 };
301 self.graphics_layer_value(layer)
302 }
303
304 pub fn rounded_alpha_mask(
309 self,
310 area_width: f32,
311 area_height: f32,
312 corner_radius: f32,
313 edge_feather: f32,
314 ) -> Self {
315 let layer = GraphicsLayer {
316 render_effect: Some(rounded_alpha_mask_effect(
317 area_width,
318 area_height,
319 corner_radius,
320 edge_feather,
321 )),
322 ..Default::default()
323 };
324 self.graphics_layer_value(layer)
325 }
326
327 pub fn gradient_fade_dst_out(
332 self,
333 area_width: f32,
334 area_height: f32,
335 spec: GradientFadeMaskSpec,
336 ) -> Self {
337 let layer = GraphicsLayer {
338 render_effect: Some(gradient_fade_dst_out_effect(&spec, area_width, area_height)),
339 ..Default::default()
340 };
341 self.graphics_layer_value(layer)
342 }
343}
344
345#[derive(Clone, Copy, Debug, PartialEq)]
347pub struct GlassMaterial {
348 pub blur_radius: Dp,
349 pub tint: Color,
350 pub shape: RoundedCornerShape,
351}
352
353impl GlassMaterial {
354 pub fn new(blur_radius: Dp, tint: Color, shape: RoundedCornerShape) -> Self {
355 Self {
356 blur_radius,
357 tint,
358 shape,
359 }
360 }
361}