From f793ec79ac55aa8d95356fb894e4120341699be5 Mon Sep 17 00:00:00 2001 From: Joscha Date: Thu, 16 Feb 2023 09:58:18 +0100 Subject: [PATCH] Add Text widget --- src/lib.rs | 1 + src/widgets.rs | 3 ++ src/widgets/text.rs | 92 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 src/widgets.rs create mode 100644 src/widgets/text.rs diff --git a/src/lib.rs b/src/lib.rs index 8b4f086..d1312f1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,6 +14,7 @@ mod frame; mod styled; mod terminal; mod widget; +pub mod widgets; mod widthdb; mod wrap; diff --git a/src/widgets.rs b/src/widgets.rs new file mode 100644 index 0000000..3021f9a --- /dev/null +++ b/src/widgets.rs @@ -0,0 +1,3 @@ +mod text; + +pub use text::*; diff --git a/src/widgets/text.rs b/src/widgets/text.rs new file mode 100644 index 0000000..94a74c3 --- /dev/null +++ b/src/widgets/text.rs @@ -0,0 +1,92 @@ +use async_trait::async_trait; + +use crate::{AsyncWidget, Frame, Pos, Size, Styled, Widget, WidthDb}; + +pub struct Text { + styled: Styled, + wrap: bool, +} + +impl Text { + pub fn new>(styled: S) -> Self { + Self { + styled: styled.into(), + wrap: true, + } + } + + pub fn wrap(mut self, wrap: bool) -> Self { + self.wrap = wrap; + self + } + + fn wrapped(&self, widthdb: &mut WidthDb, max_width: Option) -> Vec { + let max_width = max_width + .filter(|_| self.wrap) + .map(|w| w as usize) + .unwrap_or(usize::MAX); + + let indices = widthdb.wrap(self.styled.text(), max_width); + self.styled.clone().split_at_indices(&indices) + } + + fn size(&self, widthdb: &mut WidthDb, max_width: Option) -> Size { + let lines = self.wrapped(widthdb, max_width); + + let min_width = lines + .iter() + .map(|l| widthdb.width(l.text().trim_end())) + .max() + .unwrap_or(0); + let min_height = lines.len(); + + let min_width: u16 = min_width.try_into().unwrap_or(u16::MAX); + let min_height: u16 = min_height.try_into().unwrap_or(u16::MAX); + Size::new(min_width, min_height) + } + + fn draw(self, frame: &mut Frame) { + let size = frame.size(); + for (i, line) in self + .wrapped(frame.widthdb(), Some(size.width)) + .into_iter() + .enumerate() + { + let i: i32 = i.try_into().unwrap_or(i32::MAX); + frame.write(Pos::new(0, i), line); + } + } +} + +impl Widget for Text { + fn size( + &self, + frame: &mut Frame, + max_width: Option, + _max_height: Option, + ) -> Result { + Ok(self.size(frame.widthdb(), max_width)) + } + + fn draw(self, frame: &mut Frame) -> Result<(), E> { + self.draw(frame); + Ok(()) + } +} + +#[async_trait] +impl AsyncWidget for Text { + async fn size( + &self, + frame: &mut Frame, + max_width: Option, + _max_height: Option, + ) -> Result { + Ok(self.size(frame.widthdb(), max_width)) + } + + async fn draw(self, frame: &mut Frame) -> Result<(), E> { + self.draw(frame); + Ok(()) + } +}