feat(layout): add Rect::contains method (#882)

This is useful for performing hit tests (i.e. did the user click in an
area).
This commit is contained in:
Josh McKinney 2024-01-29 04:44:22 -08:00 committed by GitHub
parent 1cbe1f52ab
commit bbcfa55a88
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -221,6 +221,24 @@ impl Rect {
&& self.bottom() > other.y
}
/// Returns true if the given position is inside the rect.
///
/// The position is considered inside the rect if it is on the rect's border.
///
/// # Examples
///
/// ```rust
/// # use ratatui::{prelude::*, layout::Position};
/// let rect = Rect::new(1, 2, 3, 4);
/// assert!(rect.contains(Position { x: 1, y: 2 }));
/// ````
pub const fn contains(self, position: Position) -> bool {
position.x >= self.x
&& position.x < self.right()
&& position.y >= self.y
&& position.y < self.bottom()
}
/// Split the rect into a number of sub-rects according to the given [`Layout`]`.
///
/// An ergonomic wrapper around [`Layout::split`] that returns an array of `Rect`s instead of
@ -490,6 +508,26 @@ mod tests {
assert!(!Rect::new(1, 2, 3, 4).intersects(Rect::new(5, 6, 7, 8)));
}
// the bounds of this rect are x: [1..=3], y: [2..=5]
#[rstest]
#[case::inside_top_left(Rect::new(1, 2, 3, 4), Position { x: 1, y: 2 }, true)]
#[case::inside_top_right(Rect::new(1, 2, 3, 4), Position { x: 3, y: 2 }, true)]
#[case::inside_bottom_left(Rect::new(1, 2, 3, 4), Position { x: 1, y: 5 }, true)]
#[case::inside_bottom_right(Rect::new(1, 2, 3, 4), Position { x: 3, y: 5 }, true)]
#[case::outside_left(Rect::new(1, 2, 3, 4), Position { x: 0, y: 2 }, false)]
#[case::outside_right(Rect::new(1, 2, 3, 4), Position { x: 4, y: 2 }, false)]
#[case::outside_top(Rect::new(1, 2, 3, 4), Position { x: 1, y: 1 }, false)]
#[case::outside_bottom(Rect::new(1, 2, 3, 4), Position { x: 1, y: 6 }, false)]
#[case::outside_top_left(Rect::new(1, 2, 3, 4), Position { x: 0, y: 1 }, false)]
#[case::outside_bottom_right(Rect::new(1, 2, 3, 4), Position { x: 4, y: 6 }, false)]
fn contains(#[case] rect: Rect, #[case] position: Position, #[case] expected: bool) {
assert_eq!(
rect.contains(position),
expected,
"rect: {rect:?}, position: {position:?}",
);
}
#[test]
fn size_truncation() {
for width in 256u16..300u16 {