@@ -24,7 +24,7 @@ pub struct Margin {
26/// A simple rectangle used in the computation of the layout and to give widgets an hint about the
26/// A simple rectangle used in the computation of the layout and to give widgets an hint about the
27−/// area they are supposed to render to.
27+/// area they are supposed to render to. (x, y) = (0, 0) is at the top left corner of the screen.
28#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
28#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
29pub struct Rect {
29pub struct Rect {
30 pub x: u16,
30 pub x: u16,
@@ -92,6 +92,57 @@ impl Rect {
92 self.y.saturating_add(self.height)
92 self.y.saturating_add(self.height)
95+ // Returns a new Rect with width reduced from the left side.
96+ // This changes the `x` coordinate and clamps it to the right
97+ // edge of the original Rect.
98+ pub fn clip_left(self, width: u16) -> Rect {
99+ let width = std::cmp::min(width, self.width);
101+ x: self.x.saturating_add(width),
102+ width: self.width.saturating_sub(width),
107+ // Returns a new Rect with width reduced from the right side.
108+ // This does _not_ change the `x` coordinate.
109+ pub fn clip_right(self, width: u16) -> Rect {
111+ width: self.width.saturating_sub(width),
116+ // Returns a new Rect with height reduced from the top.
117+ // This changes the `y` coordinate and clamps it to the bottom
118+ // edge of the original Rect.
119+ pub fn clip_top(self, height: u16) -> Rect {
120+ let height = std::cmp::min(height, self.height);
122+ y: self.y.saturating_add(height),
123+ height: self.height.saturating_sub(height),
128+ // Returns a new Rect with height reduced from the bottom.
129+ // This does _not_ change the `y` coordinate.
130+ pub fn clip_bottom(self, height: u16) -> Rect {
132+ height: self.height.saturating_sub(height),
137+ pub fn with_height(self, height: u16) -> Rect {
138+ // new height may make area > u16::max_value, so use new()
139+ Self::new(self.x, self.y, self.width, height)
142+ pub fn with_width(self, width: u16) -> Rect {
143+ Self::new(self.x, self.y, width, self.height)
95 pub fn inner(self, margin: &Margin) -> Rect {
146 pub fn inner(self, margin: &Margin) -> Rect {
96 if self.width < 2 * margin.horizontal || self.height < 2 * margin.vertical {
147 if self.width < 2 * margin.horizontal || self.height < 2 * margin.vertical {
97 Rect::default()
148 Rect::default()
@@ -495,6 +546,40 @@ mod tests {
495 assert_eq!(rect.height, 100);
546 assert_eq!(rect.height, 100);
550+ fn test_rect_chop_from_left() {
551+ let rect = Rect::new(0, 0, 20, 30);
552+ assert_eq!(Rect::new(10, 0, 10, 30), rect.clip_left(10));
554+ Rect::new(20, 0, 0, 30),
556+ "x should be clamped to original width if new width is bigger"
561+ fn test_rect_chop_from_right() {
562+ let rect = Rect::new(0, 0, 20, 30);
563+ assert_eq!(Rect::new(0, 0, 10, 30), rect.clip_right(10));
567+ fn test_rect_chop_from_top() {
568+ let rect = Rect::new(0, 0, 20, 30);
569+ assert_eq!(Rect::new(0, 10, 20, 20), rect.clip_top(10));
571+ Rect::new(0, 30, 20, 0),
573+ "y should be clamped to original height if new height is bigger"
578+ fn test_rect_chop_from_bottom() {
579+ let rect = Rect::new(0, 0, 20, 30);
580+ assert_eq!(Rect::new(0, 0, 20, 20), rect.clip_bottom(10));
498 fn styles() -> Vec<Style> {
583 fn styles() -> Vec<Style> {
500 Style::default(),
585 Style::default(),