From 3f8a9079ee42f799d2bdb7c7fcb1bbb7ef4433df Mon Sep 17 00:00:00 2001 From: Robin Nehls Date: Fri, 25 May 2018 13:21:36 +0200 Subject: [PATCH] [widgets] implement text alignment for paragraph widget --- Cargo.toml | 1 + src/lib.rs | 1 + src/widgets/paragraph.rs | 108 +++++++++++++++++++++++++++++---------- 3 files changed, 82 insertions(+), 28 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d272d23f..018ff5fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ default = ["termion"] [dependencies] bitflags = "1.0.1" cassowary = "0.3.0" +itertools = "0.7.8" log = "0.4.1" unicode-segmentation = "1.2.0" unicode-width = "0.1.4" diff --git a/src/lib.rs b/src/lib.rs index 7917fbd7..3d117d22 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -156,6 +156,7 @@ #[macro_use] extern crate bitflags; extern crate cassowary; +extern crate itertools; #[macro_use] extern crate log; extern crate unicode_segmentation; diff --git a/src/widgets/paragraph.rs b/src/widgets/paragraph.rs index 3355992e..cbe52e80 100644 --- a/src/widgets/paragraph.rs +++ b/src/widgets/paragraph.rs @@ -1,9 +1,10 @@ +use itertools::{multipeek, MultiPeek}; use unicode_segmentation::UnicodeSegmentation; use unicode_width::UnicodeWidthStr; use buffer::Buffer; use layout::Rect; -use style::{Color, Modifier, Style}; +use style::{Alignment, Color, Modifier, Style}; use widgets::{Block, Widget}; /// A widget to display some text. You can specify colors using commands embedded in @@ -36,6 +37,8 @@ pub struct Paragraph<'a> { raw: bool, /// Scroll scroll: u16, + /// Aligenment of the text + alignment: Alignment, } impl<'a> Default for Paragraph<'a> { @@ -47,6 +50,7 @@ impl<'a> Default for Paragraph<'a> { raw: false, text: "", scroll: 0, + alignment: Alignment::Left, } } } @@ -81,6 +85,11 @@ impl<'a> Paragraph<'a> { self.scroll = offset; self } + + pub fn alignment(&mut self, alignment: Alignment) -> &mut Paragraph<'a> { + self.alignment = alignment; + self + } } struct Parser<'a, T> @@ -236,8 +245,6 @@ impl<'a> Widget for Paragraph<'a> { self.background(&text_area, buf, self.style.bg); - let mut x = 0; - let mut y = 0; let graphemes = UnicodeSegmentation::graphemes(self.text, true); let styled: Box> = if self.raw { Box::new(graphemes.map(|g| (g, self.style))) @@ -245,38 +252,83 @@ impl<'a> Widget for Paragraph<'a> { Box::new(Parser::new(graphemes, self.style)) }; + let mut styled = multipeek(styled); + + fn get_cur_line_len<'a, I: Iterator>( + styled: &mut MultiPeek, + ) -> u16 { + let mut line_len = 0; + while match &styled.peek() { + Some(&(x, _)) => x != "\n", + None => false, + } { + line_len += 1; + } + line_len + }; + + let mut x = match self.alignment { + Alignment::Center => { + (text_area.width / 2).saturating_sub(get_cur_line_len(&mut styled) / 2) + } + Alignment::Right => (text_area.width).saturating_sub(get_cur_line_len(&mut styled)), + Alignment::Left => 0, + }; + let mut y = 0; + let mut remove_leading_whitespaces = false; - for (string, style) in styled { - if string == "\n" { - x = 0; - y += 1; - continue; - } - if x >= text_area.width { - if self.wrapping { - x = 0; + loop { + if let Some((string, style)) = styled.next() { + if string == "\n" { + x = match self.alignment { + Alignment::Center => { + (text_area.width / 2).saturating_sub(get_cur_line_len(&mut styled) / 2) + } + + Alignment::Right => { + (text_area.width).saturating_sub(get_cur_line_len(&mut styled)) + } + Alignment::Left => 0, + }; y += 1; - remove_leading_whitespaces = true + continue; } - } + if x >= text_area.width { + if self.wrapping { + x = match self.alignment { + Alignment::Center => (text_area.width / 2) + .saturating_sub(get_cur_line_len(&mut styled) / 2), - if remove_leading_whitespaces && string == " " { - continue; - } - remove_leading_whitespaces = false; + Alignment::Right => { + (text_area.width).saturating_sub(get_cur_line_len(&mut styled) + 1) + } + Alignment::Left => 0, + }; + y += 1; + remove_leading_whitespaces = true + } + } - if y > text_area.height + self.scroll - 1 { + if remove_leading_whitespaces && string == " " { + continue; + } + remove_leading_whitespaces = false; + + if y > text_area.height + self.scroll - 1 { + break; + } + + if y < self.scroll { + continue; + } + + buf.get_mut(text_area.left() + x, text_area.top() + y - self.scroll) + .set_symbol(string) + .set_style(style); + x += string.width() as u16; + } else { break; } - - if y < self.scroll { - continue; - } - - buf.get_mut(text_area.left() + x, text_area.top() + y - self.scroll) - .set_symbol(string) - .set_style(style); - x += string.width() as u16; } } }