1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
use crate::prelude::*;

/// Clips the widget child to the area of the widget when set to `true`.
///
/// Any content rendered outside the widget inner bounds is clipped, hit-test shapes are also clipped. The clip is
/// rectangular and can have rounded corners if [`corner_radius`] is set. If the widget is inlined during layout the first
/// row advance and last row trail are also clipped.
///
/// [`corner_radius`]: fn@crate::corner_radius
#[property(FILL, default(false))]
pub fn clip_to_bounds(child: impl UiNode, clip: impl IntoVar<bool>) -> impl UiNode {
    let clip = clip.into_var();
    let mut corners = PxCornerRadius::zero();

    match_node(child, move |child, op| match op {
        UiNodeOp::Init => {
            WIDGET.layout().render();
        }
        UiNodeOp::Update { .. } => {
            if clip.is_new() {
                WIDGET.layout().render();
            }
        }
        UiNodeOp::Layout { wl, final_size } => {
            let bounds = child.layout(wl);

            if clip.get() {
                let c = BORDER.border_radius();
                if c != corners {
                    corners = c;
                    WIDGET.render();
                }
            }

            *final_size = bounds;
        }
        UiNodeOp::Render { frame } => {
            if clip.get() {
                frame.push_clips(
                    |c| {
                        let wgt_bounds = WIDGET.bounds();
                        let bounds = PxRect::from_size(wgt_bounds.inner_size());

                        if corners != PxCornerRadius::zero() {
                            c.push_clip_rounded_rect(bounds, corners, false, true);
                        } else {
                            c.push_clip_rect(bounds, false, true);
                        }

                        if let Some(inline) = wgt_bounds.inline() {
                            for r in inline.negative_space().iter() {
                                c.push_clip_rect(*r, true, true);
                            }
                        };
                    },
                    |f| child.render(f),
                );
            } else {
                child.render(frame);
            }
        }
        _ => {}
    })
}