1#![forbid(unsafe_code)]
2
3use sequoia_core::Length;
4use sequoia_layout::LayoutStyle;
5use sequoia_style::Backdrop;
6
7use crate::any::AnyView;
8use crate::view::{PaintCtx, View};
9
10#[derive(Clone)]
11pub struct BackdropBlur {
12 child: AnyView,
13 backdrop: Backdrop,
14}
15
16impl BackdropBlur {
17 pub fn new<V: View + 'static>(child: V, backdrop: Backdrop) -> Self {
18 Self {
19 child: AnyView::new(child),
20 backdrop,
21 }
22 }
23
24 pub fn blurred<V: View + 'static>(child: V, radius: f32) -> Self {
25 Self::new(child, Backdrop::blur(radius))
26 }
27
28 pub fn style(&self) -> Backdrop {
29 self.backdrop
30 }
31}
32
33impl View for BackdropBlur {
34 fn body(&self) -> impl View + 'static {
35 crate::views::Unit
36 }
37
38 fn children_override(&self) -> Option<Vec<AnyView>> {
39 Some(vec![self.child.clone()])
40 }
41
42 fn layout_style(&self) -> LayoutStyle {
43 LayoutStyle {
44 width: Length::Fit,
45 height: Length::Fit,
46 ..LayoutStyle::default()
47 }
48 }
49
50 fn paint_self(&self, ctx: &mut PaintCtx) {
51 ctx.push_backdrop(ctx.rect, self.backdrop);
52 }
53}
54
55#[cfg(test)]
56mod tests {
57 use super::*;
58 use crate::filter_view::FilterExt;
59 use sequoia_core::{Color, Rect, RenderList, SpanMask};
60
61 #[test]
62 fn wrapper_paints_marker_before_child() {
63 let v = BackdropBlur::blurred(crate::views::Unit, 16.0);
64 let mut list = RenderList::new();
65
66 let rect = Rect::from_xywh(10.0, 20.0, 200.0, 100.0);
67
68 list.push_backdrop(rect, 0.0, 16.0, Color::TRANSPARENT, 0.0, SpanMask::None);
69 assert!(list.has_backdrops());
70 let span = list.backdrops()[0];
71 assert_eq!(span.at, 0, "marker before child content");
72 assert_eq!(span.draw.rect, rect);
73 assert_eq!(span.draw.blur, 16.0);
74 let _ = v;
75 }
76
77 #[test]
78 fn blur_behind_is_canonical() {
79 let w = crate::views::Unit.blur_behind(16.0);
80 assert_eq!(w.style(), Backdrop::blur(16.0));
81 }
82
83 #[test]
84 fn wrapper_is_fit_like_opacity() {
85 let style = BackdropBlur::blurred(crate::views::Unit, 8.0).layout_style();
86 assert_eq!(style.width, Length::Fit);
87 assert_eq!(style.height, Length::Fit);
88 }
89}