From f9375f449c8b7bbf792c88b89903fe38d524f2e5 Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Sat, 21 Aug 2021 10:51:20 +0530 Subject: Refactor new Rect construction (#575) * Refactor new Rect construction Introduces methods that can be chained to construct new Rects out of pre-existing ones * Clamp x and y to edges in Rect chop methods * Rename Rect clipping functions--- helix-view/src/graphics.rs | 87 +++++++++++++++++++++++++++++++++++++++++++++- helix-view/src/view.rs | 7 +--- 2 files changed, 87 insertions(+), 7 deletions(-) (limited to 'helix-view/src') diff --git a/helix-view/src/graphics.rs b/helix-view/src/graphics.rs index 9a7a86c3..66013ee5 100644 --- a/helix-view/src/graphics.rs +++ b/helix-view/src/graphics.rs @@ -24,7 +24,7 @@ pub struct Margin { } /// A simple rectangle used in the computation of the layout and to give widgets an hint about the -/// area they are supposed to render to. +/// area they are supposed to render to. (x, y) = (0, 0) is at the top left corner of the screen. #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] pub struct Rect { pub x: u16, @@ -92,6 +92,57 @@ impl Rect { self.y.saturating_add(self.height) } + // Returns a new Rect with width reduced from the left side. + // This changes the `x` coordinate and clamps it to the right + // edge of the original Rect. + pub fn clip_left(self, width: u16) -> Rect { + let width = std::cmp::min(width, self.width); + Rect { + x: self.x.saturating_add(width), + width: self.width.saturating_sub(width), + ..self + } + } + + // Returns a new Rect with width reduced from the right side. + // This does _not_ change the `x` coordinate. + pub fn clip_right(self, width: u16) -> Rect { + Rect { + width: self.width.saturating_sub(width), + ..self + } + } + + // Returns a new Rect with height reduced from the top. + // This changes the `y` coordinate and clamps it to the bottom + // edge of the original Rect. + pub fn clip_top(self, height: u16) -> Rect { + let height = std::cmp::min(height, self.height); + Rect { + y: self.y.saturating_add(height), + height: self.height.saturating_sub(height), + ..self + } + } + + // Returns a new Rect with height reduced from the bottom. + // This does _not_ change the `y` coordinate. + pub fn clip_bottom(self, height: u16) -> Rect { + Rect { + height: self.height.saturating_sub(height), + ..self + } + } + + pub fn with_height(self, height: u16) -> Rect { + // new height may make area > u16::max_value, so use new() + Self::new(self.x, self.y, self.width, height) + } + + pub fn with_width(self, width: u16) -> Rect { + Self::new(self.x, self.y, width, self.height) + } + pub fn inner(self, margin: &Margin) -> Rect { if self.width < 2 * margin.horizontal || self.height < 2 * margin.vertical { Rect::default() @@ -495,6 +546,40 @@ mod tests { assert_eq!(rect.height, 100); } + #[test] + fn test_rect_chop_from_left() { + let rect = Rect::new(0, 0, 20, 30); + assert_eq!(Rect::new(10, 0, 10, 30), rect.clip_left(10)); + assert_eq!( + Rect::new(20, 0, 0, 30), + rect.clip_left(40), + "x should be clamped to original width if new width is bigger" + ); + } + + #[test] + fn test_rect_chop_from_right() { + let rect = Rect::new(0, 0, 20, 30); + assert_eq!(Rect::new(0, 0, 10, 30), rect.clip_right(10)); + } + + #[test] + fn test_rect_chop_from_top() { + let rect = Rect::new(0, 0, 20, 30); + assert_eq!(Rect::new(0, 10, 20, 20), rect.clip_top(10)); + assert_eq!( + Rect::new(0, 30, 20, 0), + rect.clip_top(50), + "y should be clamped to original height if new height is bigger" + ); + } + + #[test] + fn test_rect_chop_from_bottom() { + let rect = Rect::new(0, 0, 20, 30); + assert_eq!(Rect::new(0, 0, 20, 20), rect.clip_bottom(10)); + } + fn styles() -> Vec