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);
}
}
_ => {}
})
}