From 53a0f8d4afe6980447014f14a0ba3196c67a8f2e Mon Sep 17 00:00:00 2001 From: Joscha Date: Tue, 12 Jul 2022 09:27:16 +0200 Subject: [PATCH] Add Text widget --- src/ui.rs | 2 +- src/ui/widget.rs | 9 ------- src/ui/widgets.rs | 11 ++++++++ src/ui/widgets/text.rs | 59 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 10 deletions(-) delete mode 100644 src/ui/widget.rs create mode 100644 src/ui/widgets.rs create mode 100644 src/ui/widgets/text.rs diff --git a/src/ui.rs b/src/ui.rs index f8d6fdb..a76e13d 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -4,7 +4,7 @@ mod list; mod room; mod rooms; mod util; -mod widget; +mod widgets; use std::sync::{Arc, Weak}; use std::time::Duration; diff --git a/src/ui/widget.rs b/src/ui/widget.rs deleted file mode 100644 index b422beb..0000000 --- a/src/ui/widget.rs +++ /dev/null @@ -1,9 +0,0 @@ -use async_trait::async_trait; -use toss::frame::{Frame, Pos, Size}; - -#[async_trait] -pub trait Widget { - fn size(max_width: Option, max_height: Option) -> Size; - - async fn render(frame: &mut Frame, pos: Pos, size: Size); -} diff --git a/src/ui/widgets.rs b/src/ui/widgets.rs new file mode 100644 index 0000000..bdb0809 --- /dev/null +++ b/src/ui/widgets.rs @@ -0,0 +1,11 @@ +pub mod text; + +use async_trait::async_trait; +use toss::frame::{Frame, Pos, Size}; + +#[async_trait] +pub trait Widget { + fn size(&self, frame: &mut Frame, max_width: Option, max_height: Option) -> Size; + + async fn render(&self, frame: &mut Frame, pos: Pos, size: Size); +} diff --git a/src/ui/widgets/text.rs b/src/ui/widgets/text.rs new file mode 100644 index 0000000..267f447 --- /dev/null +++ b/src/ui/widgets/text.rs @@ -0,0 +1,59 @@ +use async_trait::async_trait; +use toss::frame::{Frame, Pos, Size}; +use toss::styled::Styled; + +use super::Widget; + +pub struct Text { + styled: Styled, + wrap: bool, +} + +impl Text { + pub fn new>(styled: S) -> Self { + Self { + styled: styled.into(), + wrap: false, + } + } + + pub fn wrap(mut self) -> Self { + self.wrap = true; + self + } + + fn wrapped(&self, frame: &mut Frame, max_width: Option) -> Vec { + let max_width = if self.wrap { + max_width.map(|w| w as usize).unwrap_or(usize::MAX) + } else { + usize::MAX + }; + + let indices = frame.wrap(&self.styled.text(), max_width); + self.styled.clone().split_at_indices(&indices) + } +} + +#[async_trait] +impl Widget for Text { + fn size(&self, frame: &mut Frame, max_width: Option, _max_height: Option) -> Size { + let lines = self.wrapped(frame, max_width); + let min_width = lines + .iter() + .map(|l| frame.width(&l.text())) + .max() + .unwrap_or(0); + let min_height = lines.len(); + Size::new(min_width as u16, min_height as u16) + } + + async fn render(&self, frame: &mut Frame, pos: Pos, size: Size) { + for (i, line) in self + .wrapped(frame, Some(size.width)) + .into_iter() + .enumerate() + { + frame.write(pos + Pos::new(0, i as i32), line); + } + } +}