From dbafc4070011454e8b78ba3547a303491b293c80 Mon Sep 17 00:00:00 2001 From: Joscha Date: Thu, 16 Feb 2023 14:30:12 +0100 Subject: [PATCH] Add Padding widget --- src/buffer.rs | 14 +++++ src/widgets.rs | 2 + src/widgets/padding.rs | 117 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+) create mode 100644 src/widgets/padding.rs diff --git a/src/buffer.rs b/src/buffer.rs index b8b9882..4804fcb 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -16,6 +16,20 @@ impl Size { pub const fn new(width: u16, height: u16) -> Self { Self { width, height } } + + pub const fn saturating_add(self, rhs: Self) -> Self { + Self::new( + self.width.saturating_add(rhs.width), + self.height.saturating_add(rhs.height), + ) + } + + pub const fn saturating_sub(self, rhs: Self) -> Self { + Self::new( + self.width.saturating_sub(rhs.width), + self.height.saturating_sub(rhs.height), + ) + } } impl Add for Size { diff --git a/src/widgets.rs b/src/widgets.rs index 27280a5..7a938af 100644 --- a/src/widgets.rs +++ b/src/widgets.rs @@ -1,5 +1,7 @@ mod border; +mod padding; mod text; pub use border::*; +pub use padding::*; pub use text::*; diff --git a/src/widgets/padding.rs b/src/widgets/padding.rs new file mode 100644 index 0000000..9cdcb68 --- /dev/null +++ b/src/widgets/padding.rs @@ -0,0 +1,117 @@ +use async_trait::async_trait; + +use crate::{AsyncWidget, Frame, Pos, Size, Widget}; + +pub struct Padding { + inner: I, + left: u16, + right: u16, + top: u16, + bottom: u16, +} + +impl Padding { + pub fn new(inner: I) -> Self { + Self { + inner, + left: 0, + right: 0, + top: 0, + bottom: 0, + } + } + + pub fn left(mut self, amount: u16) -> Self { + self.left = amount; + self + } + + pub fn right(mut self, amount: u16) -> Self { + self.right = amount; + self + } + + pub fn top(mut self, amount: u16) -> Self { + self.top = amount; + self + } + + pub fn bottom(mut self, amount: u16) -> Self { + self.bottom = amount; + self + } + + pub fn horizontal(self, amount: u16) -> Self { + self.left(amount).right(amount) + } + + pub fn vertical(self, amount: u16) -> Self { + self.top(amount).bottom(amount) + } + + pub fn all(self, amount: u16) -> Self { + self.horizontal(amount).vertical(amount) + } + + fn pad_size(&self) -> Size { + Size::new(self.left + self.right, self.top + self.bottom) + } + + fn push_inner(&self, frame: &mut Frame) { + let size = frame.size(); + let pad_size = self.pad_size(); + let inner_size = size.saturating_sub(pad_size); + frame.push(Pos::new(self.left.into(), self.top.into()), inner_size); + } +} + +impl Widget for Padding +where + I: Widget, +{ + fn size( + &self, + frame: &mut Frame, + max_width: Option, + max_height: Option, + ) -> Result { + let pad_size = self.pad_size(); + let max_width = max_width.map(|w| w.saturating_sub(pad_size.width)); + let max_height = max_height.map(|h| h.saturating_sub(pad_size.height)); + let size = self.inner.size(frame, max_width, max_height)?; + Ok(size + pad_size) + } + + fn draw(self, frame: &mut Frame) -> Result<(), E> { + self.push_inner(frame); + self.inner.draw(frame)?; + frame.pop(); + Ok(()) + } +} + +#[async_trait] +impl AsyncWidget for Padding +where + I: AsyncWidget + Send + Sync, +{ + async fn size( + &self, + frame: &mut Frame, + max_width: Option, + max_height: Option, + ) -> Result { + let pad_size = self.pad_size(); + let max_width = max_width.map(|w| w.saturating_sub(pad_size.width)); + let max_height = max_height.map(|h| h.saturating_sub(pad_size.height)); + let size = self.inner.size(frame, max_width, max_height).await?; + Ok(size + pad_size) + } + + async fn draw(self, frame: &mut Frame) -> Result<(), E> { + self.push_inner(frame); + self.inner.draw(frame).await?; + frame.pop(); + Ok(()) + } +}