diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 874740e..e2c6e94 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -1,18 +1,12 @@ use crossterm::event::Event; -use crossterm::style::{ContentStyle, Stylize}; -use toss::{Frame, Pos, Terminal}; +use crossterm::style::Stylize; +use toss::{Frame, Pos, Style, Terminal}; fn draw(f: &mut Frame) { - f.write( - Pos::new(0, 0), - ("Hello world!", ContentStyle::default().green()), - ); + f.write(Pos::new(0, 0), ("Hello world!", Style::new().green())); f.write( Pos::new(0, 1), - ( - "Press any key to exit", - ContentStyle::default().on_dark_blue(), - ), + ("Press any key to exit", Style::new().on_dark_blue()), ); f.show_cursor(Pos::new(16, 0)); } diff --git a/examples/hello_world_widgets.rs b/examples/hello_world_widgets.rs index 9dd5e24..c495f81 100644 --- a/examples/hello_world_widgets.rs +++ b/examples/hello_world_widgets.rs @@ -1,25 +1,22 @@ use std::convert::Infallible; use crossterm::event::Event; -use crossterm::style::{ContentStyle, Stylize}; +use crossterm::style::Stylize; use toss::widgets::{BorderLook, Text}; -use toss::{Styled, Terminal, Widget, WidgetExt}; +use toss::{Style, Styled, Terminal, Widget, WidgetExt}; fn widget() -> impl Widget { - let styled = Styled::new("Hello world!", ContentStyle::default().green()) + let styled = Styled::new("Hello world!", Style::new().green()) .then_plain("\n") - .then( - "Press any key to exit", - ContentStyle::default().on_dark_blue(), - ); + .then("Press any key to exit", Style::new().on_dark_blue()); Text::new(styled) .padding() .horizontal(1) .border() .look(BorderLook::LINE_DOUBLE) - .style(ContentStyle::default().dark_red()) + .style(Style::new().dark_red()) .background() - .style(ContentStyle::default().on_dark_yellow()) + .style(Style::new().on_dark_yellow().opaque()) .float() .all(0.5) } diff --git a/examples/overlapping_graphemes.rs b/examples/overlapping_graphemes.rs index b3b07e1..562553f 100644 --- a/examples/overlapping_graphemes.rs +++ b/examples/overlapping_graphemes.rs @@ -1,14 +1,14 @@ use crossterm::event::Event; -use crossterm::style::{ContentStyle, Stylize}; -use toss::{Frame, Pos, Terminal}; +use crossterm::style::Stylize; +use toss::{Frame, Pos, Style, Terminal}; fn draw(f: &mut Frame) { f.write( Pos::new(0, 0), "Writing over wide graphemes removes the entire overwritten grapheme.", ); - let under = ContentStyle::default().white().on_dark_blue(); - let over = ContentStyle::default().black().on_dark_yellow(); + let under = Style::new().white().on_dark_blue(); + let over = Style::new().black().on_dark_yellow(); for i in 0..6 { let delta = i - 2; f.write(Pos::new(2 + i * 7, 2), ("a😀", under)); diff --git a/src/buffer.rs b/src/buffer.rs index d433aed..6d4b7b9 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -2,7 +2,7 @@ use std::ops::Range; use crossterm::style::ContentStyle; -use crate::{Pos, Size, Styled, WidthDb}; +use crate::{Pos, Size, Style, Styled, WidthDb}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct Cell { @@ -242,18 +242,16 @@ impl Buffer { let y = pos.y as u16; let mut col: usize = 0; - for (_, styled_grapheme) in styled.styled_grapheme_indices() { + for (_, style, grapheme) in styled.styled_grapheme_indices() { let x = pos.x + col as i32; - let g = *styled_grapheme.content(); - let style = *styled_grapheme.style(); - let width = widthdb.grapheme_width(g, col); + let width = widthdb.grapheme_width(grapheme, col); col += width as usize; - if g == "\t" { + if grapheme == "\t" { for dx in 0..width { self.write_grapheme(&xrange, x + dx as i32, y, 1, " ", style); } } else if width > 0 { - self.write_grapheme(&xrange, x, y, width, g, style); + self.write_grapheme(&xrange, x, y, width, grapheme, style); } } } @@ -268,7 +266,7 @@ impl Buffer { y: u16, width: u8, grapheme: &str, - style: ContentStyle, + style: Style, ) { let min_x = xrange.start; let max_x = xrange.end - 1; // Last possible cell @@ -280,6 +278,8 @@ impl Buffer { return; // Not visible } + // TODO Merge styles + if start_x >= min_x && end_x <= max_x { // Fully visible, write actual grapheme for offset in 0..width { @@ -287,7 +287,7 @@ impl Buffer { self.erase(x, y); *self.at_mut(x, y) = Cell { content: grapheme.to_string().into_boxed_str(), - style, + style: style.content_style, width, offset, }; @@ -299,7 +299,7 @@ impl Buffer { for x in start_x..=end_x { self.erase(x, y); *self.at_mut(x, y) = Cell { - style, + style: style.content_style, ..Default::default() }; } diff --git a/src/style.rs b/src/style.rs index 2528572..56c66ce 100644 --- a/src/style.rs +++ b/src/style.rs @@ -30,15 +30,12 @@ impl Style { self } - pub fn cover(self, base: Self) -> Self { + pub fn cover(self, base: ContentStyle) -> ContentStyle { if self.opaque { - return self; + return self.content_style; } - Self { - content_style: merge_cs(base.content_style, self.content_style), - opaque: base.opaque, - } + merge_cs(base, self.content_style) } } diff --git a/src/styled.rs b/src/styled.rs index 425a717..33a8285 100644 --- a/src/styled.rs +++ b/src/styled.rs @@ -1,19 +1,20 @@ use std::iter::Peekable; use std::slice; -use crossterm::style::{ContentStyle, StyledContent}; use unicode_segmentation::{GraphemeIndices, Graphemes, UnicodeSegmentation}; +use crate::Style; + #[derive(Debug, Default, Clone)] pub struct Styled { text: String, /// List of `(style, until)` tuples. The style should be applied to all /// chars in the range `prev_until..until`. - styles: Vec<(ContentStyle, usize)>, + styles: Vec<(Style, usize)>, } impl Styled { - pub fn new>(text: S, style: ContentStyle) -> Self { + pub fn new>(text: S, style: Style) -> Self { Self::default().then(text, style) } @@ -21,7 +22,7 @@ impl Styled { Self::default().then_plain(text) } - pub fn then>(mut self, text: S, style: ContentStyle) -> Self { + pub fn then>(mut self, text: S, style: Style) -> Self { let text = text.as_ref(); if !text.is_empty() { self.text.push_str(text); @@ -31,7 +32,7 @@ impl Styled { } pub fn then_plain>(self, text: S) -> Self { - self.then(text, ContentStyle::default()) + self.then(text, Style::new()) } pub fn and_then(mut self, mut other: Self) -> Self { @@ -121,11 +122,11 @@ impl Styled { pub struct StyledGraphemeIndices<'a> { text: GraphemeIndices<'a>, - styles: Peekable>, + styles: Peekable>, } impl<'a> Iterator for StyledGraphemeIndices<'a> { - type Item = (usize, StyledContent<&'a str>); + type Item = (usize, Style, &'a str); fn next(&mut self) -> Option { let (gi, grapheme) = self.text.next()?; @@ -134,7 +135,7 @@ impl<'a> Iterator for StyledGraphemeIndices<'a> { self.styles.next(); (style, until) = **self.styles.peek().expect("styles cover entire text"); } - Some((gi, StyledContent::new(style, grapheme))) + Some((gi, style, grapheme)) } } @@ -177,14 +178,14 @@ impl> From<(S,)> for Styled { } } -impl> From<(S, ContentStyle)> for Styled { - fn from((text, style): (S, ContentStyle)) -> Self { +impl> From<(S, Style)> for Styled { + fn from((text, style): (S, Style)) -> Self { Self::new(text, style) } } -impl> From<&[(S, ContentStyle)]> for Styled { - fn from(segments: &[(S, ContentStyle)]) -> Self { +impl> From<&[(S, Style)]> for Styled { + fn from(segments: &[(S, Style)]) -> Self { let mut result = Self::default(); for (text, style) in segments { result = result.then(text, *style); diff --git a/src/widgets/background.rs b/src/widgets/background.rs index 5fd91e8..78f362b 100644 --- a/src/widgets/background.rs +++ b/src/widgets/background.rs @@ -1,22 +1,21 @@ use async_trait::async_trait; -use crossterm::style::ContentStyle; -use crate::{AsyncWidget, Frame, Pos, Size, Widget}; +use crate::{AsyncWidget, Frame, Pos, Size, Style, Widget}; pub struct Background { inner: I, - style: ContentStyle, + style: Style, } impl Background { pub fn new(inner: I) -> Self { Self { inner, - style: ContentStyle::default(), + style: Style::default(), } } - pub fn style(mut self, style: ContentStyle) -> Self { + pub fn style(mut self, style: Style) -> Self { self.style = style; self } diff --git a/src/widgets/border.rs b/src/widgets/border.rs index 6b7d02e..fe6afbc 100644 --- a/src/widgets/border.rs +++ b/src/widgets/border.rs @@ -1,7 +1,6 @@ use async_trait::async_trait; -use crossterm::style::ContentStyle; -use crate::{AsyncWidget, Frame, Pos, Size, Widget}; +use crate::{AsyncWidget, Frame, Pos, Size, Style, Widget}; #[derive(Debug, Clone, Copy)] pub struct BorderLook { @@ -90,7 +89,7 @@ impl Default for BorderLook { pub struct Border { inner: I, look: BorderLook, - style: ContentStyle, + style: Style, } impl Border { @@ -98,7 +97,7 @@ impl Border { Self { inner, look: BorderLook::default(), - style: ContentStyle::default(), + style: Style::default(), } } @@ -107,7 +106,7 @@ impl Border { self } - pub fn style(mut self, style: ContentStyle) -> Self { + pub fn style(mut self, style: Style) -> Self { self.style = style; self }