diff --git a/src/ui/widgets.rs b/src/ui/widgets.rs index 1b93931..a95ba5d 100644 --- a/src/ui/widgets.rs +++ b/src/ui/widgets.rs @@ -3,6 +3,7 @@ pub mod border; pub mod empty; pub mod join; pub mod list; +pub mod padding; pub mod rules; pub mod text; diff --git a/src/ui/widgets/padding.rs b/src/ui/widgets/padding.rs new file mode 100644 index 0000000..7e30b5a --- /dev/null +++ b/src/ui/widgets/padding.rs @@ -0,0 +1,73 @@ +use async_trait::async_trait; +use toss::frame::{Frame, Pos, Size}; + +use super::{BoxedWidget, Widget}; + +pub struct Padding { + inner: BoxedWidget, + left: u16, + right: u16, + top: u16, + bottom: u16, +} + +impl Padding { + pub fn new>(inner: W) -> Self { + Self { + inner: inner.into(), + 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 + } +} + +#[async_trait] +impl Widget for Padding { + fn size(&self, frame: &mut Frame, max_width: Option, max_height: Option) -> Size { + let horizontal = self.left + self.right; + let vertical = self.top + self.bottom; + + let max_width = max_width.map(|w| w.saturating_sub(horizontal)); + let max_height = max_height.map(|h| h.saturating_sub(vertical)); + + let size = self.inner.size(frame, max_width, max_height); + + size + Size::new(horizontal, vertical) + } + + async fn render(self: Box, frame: &mut Frame) { + let size = frame.size(); + + let inner_pos = Pos::new(self.left.into(), self.top.into()); + let inner_size = Size::new( + size.width.saturating_sub(self.left + self.right), + size.height.saturating_sub(self.top + self.bottom), + ); + + frame.push(inner_pos, inner_size); + self.inner.render(frame).await; + frame.pop(); + } +}