feat: accept Color and Modifier for all Styles (#720)

* feat: accept Color and Modifier for all Styles

All style related methods now accept `S: Into<Style>` instead of
`Style`.
`Color` and `Modifier` implement `Into<Style>` so this is allows for
more ergonomic usage. E.g.:

```rust
Line::styled("hello", Style::new().red());
Line::styled("world", Style::new().bold());

// can now be simplified to

Line::styled("hello", Color::Red);
Line::styled("world", Modifier::BOLD);
```

Fixes https://github.com/ratatui-org/ratatui/issues/694

BREAKING CHANGE: All style related methods now accept `S: Into<Style>`
instead of `Style`. This means that if you are already passing an
ambiguous type that implements `Into<Style>` you will need to remove
the `.into()` call.

`Block` style methods can no longer be called from a const context as
trait functions cannot (yet) be const.

* feat: add tuple conversions to Style

Adds conversions for various Color and Modifier combinations

* chore: add unit tests
This commit is contained in:
Josh McKinney 2023-12-31 10:01:06 -08:00 committed by GitHub
parent a62632a947
commit 8f56fabcdd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 656 additions and 195 deletions

View File

@ -12,6 +12,7 @@ This is a quick summary of the sections below:
- [v0.26.0 (unreleased)](#v0260-unreleased)
- `Line` now has an extra `style` field which applies the style to the entire line
- `Block` style methods cannot be created in a const context
- [v0.25.0](#v0250)
- Removed `Axis::title_style` and `Buffer::set_background`
- `List::new()` now accepts `IntoIterator<Item = Into<ListItem<'a>>>`
@ -43,6 +44,14 @@ This is a quick summary of the sections below:
## v0.26.0 (unreleased)
### `Block` style methods cannot be used in a const context ([#720])
[#720]: https://github.com/ratatui-org/ratatui/pull/720
Previously the `style()`, `border_style()` and `title_style()` methods could be used to create a
`Block` in a constant context. These now accept `Into<Style>` instead of `Style`. These methods no
longer can be called from a constant context.
### `Line` now has a `style` field that applies to the entire line ([#708])
[#708]: https://github.com/ratatui-org/ratatui/pull/708

View File

@ -175,7 +175,7 @@ fn make_dates(current_year: i32) -> CalendarEventStore {
mod cals {
use super::*;
pub(super) fn get_cal<'a, S: DateStyler>(m: Month, y: i32, es: S) -> Monthly<'a, S> {
pub(super) fn get_cal<'a, DS: DateStyler>(m: Month, y: i32, es: DS) -> Monthly<'a, DS> {
use Month::*;
match m {
May => example1(m, y, es),
@ -188,7 +188,7 @@ mod cals {
}
}
fn default<'a, S: DateStyler>(m: Month, y: i32, es: S) -> Monthly<'a, S> {
fn default<'a, DS: DateStyler>(m: Month, y: i32, es: DS) -> Monthly<'a, DS> {
let default_style = Style::default()
.add_modifier(Modifier::BOLD)
.bg(Color::Rgb(50, 50, 50));
@ -198,7 +198,7 @@ mod cals {
.default_style(default_style)
}
fn example1<'a, S: DateStyler>(m: Month, y: i32, es: S) -> Monthly<'a, S> {
fn example1<'a, DS: DateStyler>(m: Month, y: i32, es: DS) -> Monthly<'a, DS> {
let default_style = Style::default()
.add_modifier(Modifier::BOLD)
.bg(Color::Rgb(50, 50, 50));
@ -209,7 +209,7 @@ mod cals {
.show_month_header(Style::default())
}
fn example2<'a, S: DateStyler>(m: Month, y: i32, es: S) -> Monthly<'a, S> {
fn example2<'a, DS: DateStyler>(m: Month, y: i32, es: DS) -> Monthly<'a, DS> {
let header_style = Style::default()
.add_modifier(Modifier::BOLD)
.add_modifier(Modifier::DIM)
@ -225,7 +225,7 @@ mod cals {
.show_month_header(Style::default())
}
fn example3<'a, S: DateStyler>(m: Month, y: i32, es: S) -> Monthly<'a, S> {
fn example3<'a, DS: DateStyler>(m: Month, y: i32, es: DS) -> Monthly<'a, DS> {
let header_style = Style::default()
.add_modifier(Modifier::BOLD)
.fg(Color::Green);
@ -241,7 +241,7 @@ mod cals {
.show_month_header(Style::default())
}
fn example4<'a, S: DateStyler>(m: Month, y: i32, es: S) -> Monthly<'a, S> {
fn example4<'a, DS: DateStyler>(m: Month, y: i32, es: DS) -> Monthly<'a, DS> {
let header_style = Style::default()
.add_modifier(Modifier::BOLD)
.fg(Color::Green);
@ -255,7 +255,7 @@ mod cals {
.default_style(default_style)
}
fn example5<'a, S: DateStyler>(m: Month, y: i32, es: S) -> Monthly<'a, S> {
fn example5<'a, DS: DateStyler>(m: Month, y: i32, es: DS) -> Monthly<'a, DS> {
let header_style = Style::default()
.add_modifier(Modifier::BOLD)
.fg(Color::Green);

View File

@ -1,3 +1,6 @@
#![warn(missing_docs)]
//! A module for the [`Buffer`] and [`Cell`] types.
mod assert;
#[allow(clippy::module_inception)]
mod buffer;

View File

@ -183,26 +183,35 @@ impl Buffer {
}
/// Print a string, starting at the position (x, y)
pub fn set_string<S>(&mut self, x: u16, y: u16, string: S, style: Style)
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
pub fn set_string<T, S>(&mut self, x: u16, y: u16, string: T, style: S)
where
S: AsRef<str>,
T: AsRef<str>,
S: Into<Style>,
{
self.set_stringn(x, y, string, usize::MAX, style);
self.set_stringn(x, y, string, usize::MAX, style.into());
}
/// Print at most the first n characters of a string if enough space is available
/// until the end of the line
pub fn set_stringn<S>(
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
pub fn set_stringn<T, S>(
&mut self,
x: u16,
y: u16,
string: S,
string: T,
width: usize,
style: Style,
style: S,
) -> (u16, u16)
where
S: AsRef<str>,
T: AsRef<str>,
S: Into<Style>,
{
let style = style.into();
let mut index = self.index_of(x, y);
let mut x_offset = x as usize;
let graphemes = UnicodeSegmentation::graphemes(string.as_ref(), true);
@ -230,6 +239,7 @@ impl Buffer {
(x_offset as u16, y)
}
/// Print a line, starting at the position (x, y)
pub fn set_line(&mut self, x: u16, y: u16, line: &Line<'_>, width: u16) -> (u16, u16) {
let mut remaining_width = width;
let mut x = x;
@ -251,12 +261,17 @@ impl Buffer {
(x, y)
}
/// Print a span, starting at the position (x, y)
pub fn set_span(&mut self, x: u16, y: u16, span: &Span<'_>, width: u16) -> (u16, u16) {
self.set_stringn(x, y, span.content.as_ref(), width as usize, span.style)
}
/// Set the style of all cells in the given area.
pub fn set_style(&mut self, area: Rect, style: Style) {
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
pub fn set_style<S: Into<Style>>(&mut self, area: Rect, style: S) {
let style = style.into();
let area = self.area.intersection(area);
for y in area.top()..area.bottom() {
for x in area.left()..area.right() {

View File

@ -12,44 +12,68 @@ pub struct Cell {
the value. Use `Cell::set_symbol` to update the field. Use `Cell::default` to \
create `Cell` instance"
)]
/// The string to be drawn in the cell.
///
/// This accepts unicode grapheme clusters which might take up more than one cell.
pub symbol: String,
/// The foreground color of the cell.
pub fg: Color,
/// The background color of the cell.
pub bg: Color,
/// The underline color of the cell.
///
/// This is only used when the `underline-color` feature is enabled.
#[cfg(feature = "underline-color")]
pub underline_color: Color,
/// The modifier of the cell.
pub modifier: Modifier,
/// Whether the cell should be skipped when copying (diffing) the buffer to the screen.
pub skip: bool,
}
#[allow(deprecated)] // For Cell::symbol
impl Cell {
/// Gets the symbol of the cell.
pub fn symbol(&self) -> &str {
self.symbol.as_str()
}
/// Sets the symbol of the cell.
pub fn set_symbol(&mut self, symbol: &str) -> &mut Cell {
self.symbol.clear();
self.symbol.push_str(symbol);
self
}
/// Sets the symbol of the cell to a single character.
pub fn set_char(&mut self, ch: char) -> &mut Cell {
self.symbol.clear();
self.symbol.push(ch);
self
}
/// Sets the foreground color of the cell.
pub fn set_fg(&mut self, color: Color) -> &mut Cell {
self.fg = color;
self
}
/// Sets the background color of the cell.
pub fn set_bg(&mut self, color: Color) -> &mut Cell {
self.bg = color;
self
}
pub fn set_style(&mut self, style: Style) -> &mut Cell {
/// Sets the style of the cell.
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
pub fn set_style<S: Into<Style>>(&mut self, style: S) -> &mut Cell {
let style = style.into();
if let Some(c) = style.fg {
self.fg = c;
}
@ -65,21 +89,20 @@ impl Cell {
self
}
#[cfg(feature = "underline-color")]
/// Returns the style of the cell.
pub fn style(&self) -> Style {
Style::default()
#[cfg(feature = "underline-color")]
return Style::default()
.fg(self.fg)
.bg(self.bg)
.underline_color(self.underline_color)
.add_modifier(self.modifier)
}
.add_modifier(self.modifier);
#[cfg(not(feature = "underline-color"))]
pub fn style(&self) -> Style {
Style::default()
#[cfg(not(feature = "underline-color"))]
return Style::default()
.fg(self.fg)
.bg(self.bg)
.add_modifier(self.modifier)
.add_modifier(self.modifier);
}
/// Sets the cell to be skipped when copying (diffing) the buffer to the screen.
@ -91,6 +114,7 @@ impl Cell {
self
}
/// Resets the cell to the default state.
pub fn reset(&mut self) {
self.symbol.clear();
self.symbol.push(' ');

View File

@ -82,6 +82,9 @@ bitflags! {
///
/// They are bitflags so they can easily be composed.
///
/// `From<Modifier> for Style` is implemented so you can use `Modifier` anywhere that accepts
/// `Into<Style>`.
///
/// ## Examples
///
/// ```rust
@ -138,6 +141,20 @@ impl fmt::Debug for Modifier {
///
/// For more information about the style shorthands, see the [`Stylize`] trait.
///
/// We implement conversions from [`Color`] and [`Modifier`] to [`Style`] so you can use them
/// anywhere that accepts `Into<Style>`.
///
/// ```rust
/// # use ratatui::prelude::*;
/// Line::styled("hello", Style::new().fg(Color::Red));
/// // simplifies to
/// Line::styled("hello", Color::Red);
///
/// Line::styled("hello", Style::new().add_modifier(Modifier::BOLD));
/// // simplifies to
/// Line::styled("hello", Modifier::BOLD);
/// ```
///
/// Styles represents an incremental change. If you apply the styles S1, S2, S3 to a cell of the
/// terminal buffer, the style of this cell will be the result of the merge of S1, S2 and S3, not
/// just S3.
@ -227,10 +244,11 @@ impl Styled for Style {
*self
}
fn set_style(self, style: Style) -> Self::Item {
fn set_style<S: Into<Style>>(self, style: S) -> Self::Item {
self.patch(style)
}
}
impl Style {
pub const fn new() -> Style {
Style {
@ -366,6 +384,9 @@ impl Style {
/// Results in a combined style that is equivalent to applying the two individual styles to
/// a style one after the other.
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// ## Examples
/// ```
/// # use ratatui::prelude::*;
@ -378,7 +399,8 @@ impl Style {
/// );
/// ```
#[must_use = "`patch` returns the modified style without modifying the original"]
pub fn patch(mut self, other: Style) -> Style {
pub fn patch<S: Into<Style>>(mut self, other: S) -> Style {
let other = other.into();
self.fg = other.fg.or(self.fg);
self.bg = other.bg.or(self.bg);
@ -396,6 +418,134 @@ impl Style {
}
}
impl From<Color> for Style {
/// Creates a new `Style` with the given foreground color.
///
/// To specify a foreground and background color, use the `from((fg, bg))` constructor.
///
/// # Example
///
/// ```rust
/// # use ratatui::prelude::*;
/// let style = Style::from(Color::Red);
/// ```
fn from(color: Color) -> Self {
Self::new().fg(color)
}
}
impl From<(Color, Color)> for Style {
/// Creates a new `Style` with the given foreground and background colors.
///
/// # Example
///
/// ```rust
/// # use ratatui::prelude::*;
/// // red foreground, blue background
/// let style = Style::from((Color::Red, Color::Blue));
/// // default foreground, blue background
/// let style = Style::from((Color::Reset, Color::Blue));
/// ```
fn from((fg, bg): (Color, Color)) -> Self {
Self::new().fg(fg).bg(bg)
}
}
impl From<Modifier> for Style {
/// Creates a new `Style` with the given modifier added.
///
/// To specify multiple modifiers, use the `|` operator.
///
/// To specify modifiers to add and remove, use the `from((add_modifier, sub_modifier))`
/// constructor.
///
/// # Example
///
/// ```rust
/// # use ratatui::prelude::*;
/// // add bold and italic
/// let style = Style::from(Modifier::BOLD|Modifier::ITALIC);
fn from(modifier: Modifier) -> Self {
Self::new().add_modifier(modifier)
}
}
impl From<(Modifier, Modifier)> for Style {
/// Creates a new `Style` with the given modifiers added and removed.
///
/// # Example
///
/// ```rust
/// # use ratatui::prelude::*;
/// // add bold and italic, remove dim
/// let style = Style::from((Modifier::BOLD | Modifier::ITALIC, Modifier::DIM));
/// ```
fn from((add_modifier, sub_modifier): (Modifier, Modifier)) -> Self {
Self::new()
.add_modifier(add_modifier)
.remove_modifier(sub_modifier)
}
}
impl From<(Color, Modifier)> for Style {
/// Creates a new `Style` with the given foreground color and modifier added.
///
/// To specify multiple modifiers, use the `|` operator.
///
/// # Example
///
/// ```rust
/// # use ratatui::prelude::*;
/// // red foreground, add bold and italic
/// let style = Style::from((Color::Red, Modifier::BOLD | Modifier::ITALIC));
/// ```
fn from((fg, modifier): (Color, Modifier)) -> Self {
Self::new().fg(fg).add_modifier(modifier)
}
}
impl From<(Color, Color, Modifier)> for Style {
/// Creates a new `Style` with the given foreground and background colors and modifier added.
///
/// To specify multiple modifiers, use the `|` operator.
///
/// # Example
///
/// ```rust
/// # use ratatui::prelude::*;
/// // red foreground, blue background, add bold and italic
/// let style = Style::from((Color::Red, Color::Blue, Modifier::BOLD | Modifier::ITALIC));
/// ```
fn from((fg, bg, modifier): (Color, Color, Modifier)) -> Self {
Self::new().fg(fg).bg(bg).add_modifier(modifier)
}
}
impl From<(Color, Color, Modifier, Modifier)> for Style {
/// Creates a new `Style` with the given foreground and background colors and modifiers added
/// and removed.
///
/// # Example
///
/// ```rust
/// # use ratatui::prelude::*;
/// // red foreground, blue background, add bold and italic, remove dim
/// let style = Style::from((
/// Color::Red,
/// Color::Blue,
/// Modifier::BOLD | Modifier::ITALIC,
/// Modifier::DIM,
/// ));
/// ```
fn from((fg, bg, add_modifier, sub_modifier): (Color, Color, Modifier, Modifier)) -> Self {
Self::new()
.fg(fg)
.bg(bg)
.add_modifier(add_modifier)
.remove_modifier(sub_modifier)
}
}
#[cfg(test)]
mod tests {
use super::*;
@ -657,4 +807,79 @@ mod tests {
// reset
assert_eq!(Style::new().reset(), Style::reset());
}
#[test]
fn from_color() {
assert_eq!(Style::from(Color::Red), Style::new().fg(Color::Red));
}
#[test]
fn from_color_color() {
assert_eq!(
Style::from((Color::Red, Color::Blue)),
Style::new().fg(Color::Red).bg(Color::Blue)
);
}
#[test]
fn from_modifier() {
assert_eq!(
Style::from(Modifier::BOLD | Modifier::ITALIC),
Style::new()
.add_modifier(Modifier::BOLD)
.add_modifier(Modifier::ITALIC)
);
}
#[test]
fn from_modifier_modifier() {
assert_eq!(
Style::from((Modifier::BOLD | Modifier::ITALIC, Modifier::DIM)),
Style::new()
.add_modifier(Modifier::BOLD)
.add_modifier(Modifier::ITALIC)
.remove_modifier(Modifier::DIM)
);
}
#[test]
fn from_color_modifier() {
assert_eq!(
Style::from((Color::Red, Modifier::BOLD | Modifier::ITALIC)),
Style::new()
.fg(Color::Red)
.add_modifier(Modifier::BOLD)
.add_modifier(Modifier::ITALIC)
);
}
#[test]
fn from_color_color_modifier() {
assert_eq!(
Style::from((Color::Red, Color::Blue, Modifier::BOLD | Modifier::ITALIC)),
Style::new()
.fg(Color::Red)
.bg(Color::Blue)
.add_modifier(Modifier::BOLD)
.add_modifier(Modifier::ITALIC)
);
}
#[test]
fn from_color_color_modifier_modifier() {
assert_eq!(
Style::from((
Color::Red,
Color::Blue,
Modifier::BOLD | Modifier::ITALIC,
Modifier::DIM
)),
Style::new()
.fg(Color::Red)
.bg(Color::Blue)
.add_modifier(Modifier::BOLD)
.add_modifier(Modifier::ITALIC)
.remove_modifier(Modifier::DIM)
);
}
}

View File

@ -35,6 +35,9 @@ use std::{
/// - we support `-` and `_` and ` ` as separators for all colors
/// - we support both `gray` and `grey` spellings
///
/// `From<Color> for Style` is implemented by creating a style with the foreground color set to the
/// given color. This allows you to use colors anywhere that accepts `Into<Style>`.
///
/// # Example
///
/// ```

View File

@ -13,8 +13,14 @@ use crate::{
pub trait Styled {
type Item;
/// Returns the style of the object.
fn style(&self) -> Style;
fn set_style(self, style: Style) -> Self::Item;
/// Sets the style of the object.
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
fn set_style<S: Into<Style>>(self, style: S) -> Self::Item;
}
/// Generates two methods for each color, one for setting the foreground color (`red()`, `blue()`,
@ -209,7 +215,7 @@ impl<'a> Styled for &'a str {
Style::default()
}
fn set_style(self, style: Style) -> Self::Item {
fn set_style<S: Into<Style>>(self, style: S) -> Self::Item {
Span::styled(self, style)
}
}
@ -221,7 +227,7 @@ impl Styled for String {
Style::default()
}
fn set_style(self, style: Style) -> Self::Item {
fn set_style<S: Into<Style>>(self, style: S) -> Self::Item {
Span::styled(self, style)
}
}

View File

@ -1,4 +1,4 @@
use crate::style::{Style, Styled};
use crate::prelude::*;
/// A grapheme associated to a style.
/// Note that, although `StyledGrapheme` is the smallest divisible unit of text,
@ -12,8 +12,15 @@ pub struct StyledGrapheme<'a> {
}
impl<'a> StyledGrapheme<'a> {
pub fn new(symbol: &'a str, style: Style) -> StyledGrapheme<'a> {
StyledGrapheme { symbol, style }
/// Creates a new `StyledGrapheme` with the given symbol and style.
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
pub fn new<S: Into<Style>>(symbol: &'a str, style: S) -> StyledGrapheme<'a> {
StyledGrapheme {
symbol,
style: style.into(),
}
}
}
@ -24,8 +31,8 @@ impl<'a> Styled for StyledGrapheme<'a> {
self.style
}
fn set_style(mut self, style: Style) -> Self::Item {
self.style = style;
fn set_style<S: Into<Style>>(mut self, style: S) -> Self::Item {
self.style = style.into();
self
}
}
@ -33,7 +40,6 @@ impl<'a> Styled for StyledGrapheme<'a> {
#[cfg(test)]
mod tests {
use super::*;
use crate::prelude::*;
#[test]
fn new() {

View File

@ -120,6 +120,9 @@ impl<'a> Line<'a> {
// `content` can be any type that is convertible to [`Cow<str>`] (e.g. [`&str`], [`String`],
/// [`Cow<str>`], or your own type that implements [`Into<Cow<str>>`]).
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// # Examples
///
/// Any newlines in the content are removed.
@ -132,9 +135,10 @@ impl<'a> Line<'a> {
/// Line::styled(String::from("My text"), style);
/// Line::styled(Cow::from("test content"), style);
/// ```
pub fn styled<T>(content: T, style: Style) -> Line<'a>
pub fn styled<T, S>(content: T, style: S) -> Line<'a>
where
T: Into<Cow<'a, str>>,
S: Into<Style>,
{
Line {
spans: content
@ -142,7 +146,7 @@ impl<'a> Line<'a> {
.lines()
.map(|v| Span::raw(v.to_string()))
.collect(),
style,
style: style.into(),
..Default::default()
}
}
@ -177,13 +181,16 @@ impl<'a> Line<'a> {
/// only by the style of each [`Span`] contained in the line. For this reason, this field may
/// not be supported by all widgets (outside of the `ratatui` crate itself).
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// # Examples
/// ```rust
/// # use ratatui::prelude::*;
/// let mut line = Line::from("foo").style(Style::new().red());
/// ```
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style<T: Into<Style>>(mut self, style: T) -> Self {
pub fn style<S: Into<Style>>(mut self, style: S) -> Self {
self.style = style.into();
self
}
@ -229,6 +236,9 @@ impl<'a> Line<'a> {
/// `base_style` is the [`Style`] that will be patched with each grapheme [`Style`] to get
/// the resulting [`Style`].
///
/// `base_style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`],
/// or your own type that implements [`Into<Style>`]).
///
/// # Examples
///
/// ```rust
@ -249,11 +259,11 @@ impl<'a> Line<'a> {
/// ]
/// );
/// ```
pub fn styled_graphemes(
pub fn styled_graphemes<S: Into<Style>>(
&'a self,
base_style: Style,
base_style: S,
) -> impl Iterator<Item = StyledGrapheme<'a>> {
let style = base_style.patch(self.style);
let style = base_style.into().patch(self.style);
self.spans
.iter()
.flat_map(move |span| span.styled_graphemes(style))
@ -265,6 +275,9 @@ impl<'a> Line<'a> {
/// In contrast to [`Line::style`], this method will not overwrite the existing style, but
/// instead will add the given style's modifiers to the existing style of each `Span`.
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// # Examples
///
/// ```rust
@ -283,7 +296,8 @@ impl<'a> Line<'a> {
/// raw_line.patch_style(style);
/// assert_eq!(raw_line, styled_line);
/// ```
pub fn patch_style(&mut self, style: Style) {
pub fn patch_style<S: Into<Style>>(&mut self, style: S) {
let style = style.into();
for span in &mut self.spans {
span.patch_style(style);
}

View File

@ -119,6 +119,12 @@ impl<'a> Span<'a> {
/// Create a span with the specified style.
///
/// `content` accepts any type that is convertible to [`Cow<str>`] (e.g. `&str`, `String`,
/// `&String`, etc.).
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// # Examples
///
/// ```rust
@ -127,13 +133,14 @@ impl<'a> Span<'a> {
/// Span::styled("test content", style);
/// Span::styled(String::from("test content"), style);
/// ```
pub fn styled<T>(content: T, style: Style) -> Span<'a>
pub fn styled<T, S>(content: T, style: S) -> Span<'a>
where
T: Into<Cow<'a, str>>,
S: Into<Style>,
{
Span {
content: content.into(),
style,
style: style.into(),
}
}
@ -166,7 +173,8 @@ impl<'a> Span<'a> {
/// In contrast to [`Span::patch_style`], this method replaces the style of the span instead of
/// patching it.
///
/// Accepts any type that can be converted to [`Style`]
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// # Examples
///
@ -175,16 +183,16 @@ impl<'a> Span<'a> {
/// let mut span = Span::default().style(Style::new().green());
/// ```
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style<T>(mut self, style: T) -> Self
where
T: Into<Style>,
{
pub fn style<S: Into<Style>>(mut self, style: S) -> Self {
self.style = style.into();
self
}
/// Patches the style of the Span, adding modifiers from the given style.
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// # Example
///
/// ```rust
@ -193,7 +201,7 @@ impl<'a> Span<'a> {
/// span.patch_style(Style::new().red().on_yellow().bold());
/// assert_eq!(span.style, Style::new().red().on_yellow().italic().bold());
/// ```
pub fn patch_style(&mut self, style: Style) {
pub fn patch_style<S: Into<Style>>(&mut self, style: S) {
self.style = self.style.patch(style);
}
@ -223,6 +231,9 @@ impl<'a> Span<'a> {
/// `base_style` is the [`Style`] that will be patched with the `Span`'s `style` to get the
/// resulting [`Style`].
///
/// `base_style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`],
/// or your own type that implements [`Into<Style>`]).
///
/// # Example
///
/// ```rust
@ -243,18 +254,16 @@ impl<'a> Span<'a> {
/// ],
/// );
/// ```
pub fn styled_graphemes(
pub fn styled_graphemes<S: Into<Style>>(
&'a self,
base_style: Style,
base_style: S,
) -> impl Iterator<Item = StyledGrapheme<'a>> {
let style = base_style.into().patch(self.style);
self.content
.as_ref()
.graphemes(true)
.filter(|g| *g != "\n")
.map(move |g| StyledGrapheme {
symbol: g,
style: base_style.patch(self.style),
})
.map(move |g| StyledGrapheme { symbol: g, style })
}
}
@ -274,9 +283,8 @@ impl<'a> Styled for Span<'a> {
self.style
}
fn set_style(mut self, style: Style) -> Self {
self.style = style;
self
fn set_style<S: Into<Style>>(self, style: S) -> Self::Item {
self.style(style)
}
}

View File

@ -1,7 +1,6 @@
use std::borrow::Cow;
use super::{Line, Span};
use crate::style::Style;
use crate::prelude::*;
/// A string split over multiple lines where each line is composed of several clusters, each with
/// their own style.
@ -60,6 +59,9 @@ impl<'a> Text<'a> {
/// Create some text (potentially multiple lines) with a style.
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// # Examples
///
/// ```rust
@ -70,9 +72,10 @@ impl<'a> Text<'a> {
/// Text::styled("The first line\nThe second line", style);
/// Text::styled(String::from("The first line\nThe second line"), style);
/// ```
pub fn styled<T>(content: T, style: Style) -> Text<'a>
pub fn styled<T, S>(content: T, style: S) -> Text<'a>
where
T: Into<Cow<'a, str>>,
S: Into<Style>,
{
let mut text = Text::raw(content);
text.patch_style(style);
@ -107,6 +110,9 @@ impl<'a> Text<'a> {
/// Patches the style of each line in an existing Text, adding modifiers from the given style.
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// # Examples
///
/// ```rust
@ -121,7 +127,8 @@ impl<'a> Text<'a> {
/// raw_text.patch_style(style);
/// assert_eq!(raw_text, styled_text);
/// ```
pub fn patch_style(&mut self, style: Style) {
pub fn patch_style<S: Into<Style>>(&mut self, style: S) {
let style = style.into();
for line in &mut self.lines {
line.patch_style(style);
}

View File

@ -170,11 +170,14 @@ impl<'a> BarChart<'a> {
/// Set the default style of the bar.
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// It is also possible to set individually the style of each [`Bar`].
/// In this case the default style will be patched by the individual style
#[must_use = "method moves the value of self and returns the modified value"]
pub fn bar_style(mut self, style: Style) -> BarChart<'a> {
self.bar_style = style;
pub fn bar_style<S: Into<Style>>(mut self, style: S) -> BarChart<'a> {
self.bar_style = style.into();
self
}
@ -226,6 +229,9 @@ impl<'a> BarChart<'a> {
/// Set the default value style of the bar.
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// It is also possible to set individually the value style of each [`Bar`].
/// In this case the default value style will be patched by the individual value style
///
@ -233,13 +239,16 @@ impl<'a> BarChart<'a> {
///
/// [Bar::value_style] to set the value style individually.
#[must_use = "method moves the value of self and returns the modified value"]
pub fn value_style(mut self, style: Style) -> BarChart<'a> {
self.value_style = style;
pub fn value_style<S: Into<Style>>(mut self, style: S) -> BarChart<'a> {
self.value_style = style.into();
self
}
/// Set the default label style of the groups and bars.
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// It is also possible to set individually the label style of each [`Bar`] or [`BarGroup`].
/// In this case the default label style will be patched by the individual label style
///
@ -247,8 +256,8 @@ impl<'a> BarChart<'a> {
///
/// [Bar::label] to set the label style individually.
#[must_use = "method moves the value of self and returns the modified value"]
pub fn label_style(mut self, style: Style) -> BarChart<'a> {
self.label_style = style;
pub fn label_style<S: Into<Style>>(mut self, style: S) -> BarChart<'a> {
self.label_style = style.into();
self
}
@ -261,10 +270,13 @@ impl<'a> BarChart<'a> {
/// Set the style of the entire chart.
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// The style will be applied to everything that isn't styled (borders, bars, labels, ...).
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style(mut self, style: Style) -> BarChart<'a> {
self.style = style;
pub fn style<S: Into<Style>>(mut self, style: S) -> BarChart<'a> {
self.style = style.into();
self
}
@ -597,7 +609,7 @@ impl<'a> Styled for BarChart<'a> {
self.style
}
fn set_style(self, style: Style) -> Self {
fn set_style<S: Into<Style>>(self, style: S) -> Self::Item {
self.style(style)
}
}

View File

@ -1,6 +1,6 @@
use unicode_width::UnicodeWidthStr;
use crate::{buffer::Buffer, prelude::Rect, style::Style, text::Line};
use crate::prelude::*;
/// A bar to be shown by the [`BarChart`](crate::widgets::BarChart) widget.
///
@ -70,22 +70,27 @@ impl<'a> Bar<'a> {
/// Set the style of the bar.
///
/// This will apply to every non-styled element.
/// It can be seen and used as a default value.
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// This will apply to every non-styled element. It can be seen and used as a default value.
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style(mut self, style: Style) -> Bar<'a> {
self.style = style;
pub fn style<S: Into<Style>>(mut self, style: S) -> Bar<'a> {
self.style = style.into();
self
}
/// Set the style of the value.
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// # See also
///
/// [`Bar::value`] to set the value.
#[must_use = "method moves the value of self and returns the modified value"]
pub fn value_style(mut self, style: Style) -> Bar<'a> {
self.value_style = style;
pub fn value_style<S: Into<Style>>(mut self, style: S) -> Bar<'a> {
self.value_style = style.into();
self
}

View File

@ -13,9 +13,7 @@ use strum::{Display, EnumString};
pub use self::title::{Position, Title};
use crate::{
buffer::Buffer,
layout::{Alignment, Rect},
style::{Style, Styled},
prelude::*,
symbols::border,
widgets::{Borders, Widget},
};
@ -334,10 +332,13 @@ impl<'a> Block<'a> {
/// Applies the style to all titles.
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// If a [`Title`] already has a style, the title's style will add on top of this one.
#[must_use = "method moves the value of self and returns the modified value"]
pub const fn title_style(mut self, style: Style) -> Block<'a> {
self.titles_style = style;
pub fn title_style<S: Into<Style>>(mut self, style: S) -> Block<'a> {
self.titles_style = style.into();
self
}
@ -405,6 +406,9 @@ impl<'a> Block<'a> {
///
/// If a [`Block::style`] is defined, `border_style` will be applied on top of it.
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// # Example
///
/// This example shows a `Block` with blue borders.
@ -415,8 +419,8 @@ impl<'a> Block<'a> {
/// .border_style(Style::new().blue());
/// ```
#[must_use = "method moves the value of self and returns the modified value"]
pub const fn border_style(mut self, style: Style) -> Block<'a> {
self.border_style = style;
pub fn border_style<S: Into<Style>>(mut self, style: S) -> Block<'a> {
self.border_style = style.into();
self
}
@ -426,10 +430,13 @@ impl<'a> Block<'a> {
/// more specific style. Elements can be styled further with [`Block::title_style`] and
/// [`Block::border_style`].
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// This will also apply to the widget inside that block, unless the inner widget is styled.
#[must_use = "method moves the value of self and returns the modified value"]
pub const fn style(mut self, style: Style) -> Block<'a> {
self.style = style;
pub fn style<S: Into<Style>>(mut self, style: S) -> Block<'a> {
self.style = style.into();
self
}
@ -797,7 +804,7 @@ impl<'a> Styled for Block<'a> {
self.style
}
fn set_style(self, style: Style) -> Self::Item {
fn set_style<S: Into<Style>>(self, style: S) -> Self::Item {
self.style(style)
}
}
@ -1100,15 +1107,60 @@ mod tests {
const _DEFAULT_STYLE: Style = Style::new();
const _DEFAULT_PADDING: Padding = Padding::uniform(1);
const _DEFAULT_BLOCK: Block = Block::new()
.title_style(_DEFAULT_STYLE)
// the following methods are no longer const because they use Into<Style>
// .style(_DEFAULT_STYLE) // no longer const
// .border_style(_DEFAULT_STYLE) // no longer const
// .title_style(_DEFAULT_STYLE) // no longer const
.title_alignment(Alignment::Left)
.title_position(Position::Top)
.borders(Borders::ALL)
.border_style(_DEFAULT_STYLE)
.style(_DEFAULT_STYLE)
.padding(_DEFAULT_PADDING);
}
/// This test ensures that we have some coverage on the Style::from() implementations
#[test]
fn block_style() {
// nominal style
let block = Block::default().style(Style::new().red());
assert_eq!(block.style, Style::new().red());
// auto-convert from Color
let block = Block::default().style(Color::Red);
assert_eq!(block.style, Style::new().red());
// auto-convert from (Color, Color)
let block = Block::default().style((Color::Red, Color::Blue));
assert_eq!(block.style, Style::new().red().on_blue());
// auto-convert from Modifier
let block = Block::default().style(Modifier::BOLD | Modifier::ITALIC);
assert_eq!(block.style, Style::new().bold().italic());
// auto-convert from (Modifier, Modifier)
let block = Block::default().style((Modifier::BOLD | Modifier::ITALIC, Modifier::DIM));
assert_eq!(block.style, Style::new().bold().italic().not_dim());
// auto-convert from (Color, Modifier)
let block = Block::default().style((Color::Red, Modifier::BOLD));
assert_eq!(block.style, Style::new().red().bold());
// auto-convert from (Color, Color, Modifier)
let block = Block::default().style((Color::Red, Color::Blue, Modifier::BOLD));
assert_eq!(block.style, Style::new().red().on_blue().bold());
// auto-convert from (Color, Color, Modifier, Modifier)
let block = Block::default().style((
Color::Red,
Color::Blue,
Modifier::BOLD | Modifier::ITALIC,
Modifier::DIM,
));
assert_eq!(
block.style,
Style::new().red().on_blue().bold().italic().not_dim()
);
}
#[test]
fn can_be_stylized() {
let block = Block::default().black().on_white().bold().not_dim();

View File

@ -13,18 +13,15 @@ use std::collections::HashMap;
use time::{Date, Duration, OffsetDateTime};
use crate::{
buffer::Buffer,
layout::Rect,
style::Style,
text::Span,
prelude::*,
widgets::{Block, Widget},
};
/// Display a month calendar for the month containing `display_date`
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Monthly<'a, S: DateStyler> {
pub struct Monthly<'a, DS: DateStyler> {
display_date: Date,
events: S,
events: DS,
show_surrounding: Option<Style>,
show_weekday: Option<Style>,
show_month: Option<Style>,
@ -32,9 +29,9 @@ pub struct Monthly<'a, S: DateStyler> {
block: Option<Block<'a>>,
}
impl<'a, S: DateStyler> Monthly<'a, S> {
impl<'a, DS: DateStyler> Monthly<'a, DS> {
/// Construct a calendar for the `display_date` and highlight the `events`
pub fn new(display_date: Date, events: S) -> Self {
pub fn new(display_date: Date, events: DS) -> Self {
Self {
display_date,
events,
@ -49,32 +46,44 @@ impl<'a, S: DateStyler> Monthly<'a, S> {
/// Fill the calendar slots for days not in the current month also, this causes each line to be
/// completely filled. If there is an event style for a date, this style will be patched with
/// the event's style
pub fn show_surrounding(mut self, style: Style) -> Self {
self.show_surrounding = Some(style);
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
pub fn show_surrounding<S: Into<Style>>(mut self, style: S) -> Self {
self.show_surrounding = Some(style.into());
self
}
/// Display a header containing weekday abbreviations
pub fn show_weekdays_header(mut self, style: Style) -> Self {
self.show_weekday = Some(style);
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
pub fn show_weekdays_header<S: Into<Style>>(mut self, style: S) -> Self {
self.show_weekday = Some(style.into());
self
}
/// Display a header containing the month and year
pub fn show_month_header(mut self, style: Style) -> Self {
self.show_month = Some(style);
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
pub fn show_month_header<S: Into<Style>>(mut self, style: S) -> Self {
self.show_month = Some(style.into());
self
}
/// How to render otherwise unstyled dates
pub fn default_style(mut self, s: Style) -> Self {
self.default_style = s;
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
pub fn default_style<S: Into<Style>>(mut self, style: S) -> Self {
self.default_style = style.into();
self
}
/// Render the calendar within a [Block]
pub fn block(mut self, b: Block<'a>) -> Self {
self.block = Some(b);
pub fn block(mut self, block: Block<'a>) -> Self {
self.block = Some(block);
self
}
@ -108,7 +117,7 @@ impl<'a, S: DateStyler> Monthly<'a, S> {
}
}
impl<'a, S: DateStyler> Widget for Monthly<'a, S> {
impl<'a, DS: DateStyler> Widget for Monthly<'a, DS> {
fn render(mut self, area: Rect, buf: &mut Buffer) {
// Block is used for borders and such
// Draw that first, and use the blank area inside the block for our own purposes
@ -178,16 +187,22 @@ pub struct CalendarEventStore(pub HashMap<Date, Style>);
impl CalendarEventStore {
/// Construct a store that has the current date styled.
pub fn today(style: Style) -> Self {
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
pub fn today<S: Into<Style>>(style: S) -> Self {
let mut res = Self::default();
res.add(OffsetDateTime::now_local().unwrap().date(), style);
res.add(OffsetDateTime::now_local().unwrap().date(), style.into());
res
}
/// Add a date and style to the store
pub fn add(&mut self, date: Date, style: Style) {
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
pub fn add<S: Into<Style>>(&mut self, date: Date, style: S) {
// to simplify style nonsense, last write wins
let _ = self.0.insert(date, style);
let _ = self.0.insert(date, style.into());
}
/// Helper for trait impls

View File

@ -109,6 +109,9 @@ impl<'a> Axis<'a> {
///
/// This is a fluent setter method which must be chained or used as it consumes self
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// # Example
///
/// [`Axis`] also implements [`Stylize`](crate::style::Stylize) which mean you can style it
@ -119,8 +122,8 @@ impl<'a> Axis<'a> {
/// let axis = Axis::default().red();
/// ```
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style(mut self, style: Style) -> Axis<'a> {
self.style = style;
pub fn style<S: Into<Style>>(mut self, style: S) -> Axis<'a> {
self.style = style.into();
self
}
@ -379,6 +382,9 @@ impl<'a> Dataset<'a> {
/// The given style will be used to draw the legend and the data points. Currently the legend
/// will use the entire style whereas the data points will only use the foreground.
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// This is a fluent setter method which must be chained or used as it consumes self
///
/// # Example
@ -391,8 +397,8 @@ impl<'a> Dataset<'a> {
/// let dataset = Dataset::default().red();
/// ```
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style(mut self, style: Style) -> Dataset<'a> {
self.style = style;
pub fn style<S: Into<Style>>(mut self, style: S) -> Dataset<'a> {
self.style = style.into();
self
}
}
@ -547,12 +553,15 @@ impl<'a> Chart<'a> {
/// Sets the style of the entire chart
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// Styles of [`Axis`] and [`Dataset`] will have priority over this style.
///
/// This is a fluent setter method which must be chained or used as it consumes self
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style(mut self, style: Style) -> Chart<'a> {
self.style = style;
pub fn style<S: Into<Style>>(mut self, style: S) -> Chart<'a> {
self.style = style.into();
self
}
@ -1043,7 +1052,7 @@ impl<'a> Styled for Axis<'a> {
self.style
}
fn set_style(self, style: Style) -> Self::Item {
fn set_style<S: Into<Style>>(self, style: S) -> Self::Item {
self.style(style)
}
}
@ -1055,7 +1064,7 @@ impl<'a> Styled for Dataset<'a> {
self.style
}
fn set_style(self, style: Style) -> Self::Item {
fn set_style<S: Into<Style>>(self, style: S) -> Self::Item {
self.style(style)
}
}
@ -1067,7 +1076,7 @@ impl<'a> Styled for Chart<'a> {
self.style
}
fn set_style(self, style: Style) -> Self::Item {
fn set_style<S: Into<Style>>(self, style: S) -> Self::Item {
self.style(style)
}
}

View File

@ -128,18 +128,24 @@ impl<'a> Gauge<'a> {
/// Sets the widget style.
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// This will style the block (if any non-styled) and background of the widget (everything
/// except the bar itself). [`Block`] style set with [`Gauge::block`] takes precedence.
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style(mut self, style: Style) -> Gauge<'a> {
self.style = style;
pub fn style<S: Into<Style>>(mut self, style: S) -> Gauge<'a> {
self.style = style.into();
self
}
/// Sets the style of the bar.
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
#[must_use = "method moves the value of self and returns the modified value"]
pub fn gauge_style(mut self, style: Style) -> Gauge<'a> {
self.gauge_style = style;
pub fn gauge_style<S: Into<Style>>(mut self, style: S) -> Gauge<'a> {
self.gauge_style = style.into();
self
}
@ -323,18 +329,24 @@ impl<'a> LineGauge<'a> {
/// Sets the widget style.
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// This will style everything except the bar itself, so basically the block (if any) and
/// background.
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style(mut self, style: Style) -> Self {
self.style = style;
pub fn style<S: Into<Style>>(mut self, style: S) -> Self {
self.style = style.into();
self
}
/// Sets the style of the bar.
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
#[must_use = "method moves the value of self and returns the modified value"]
pub fn gauge_style(mut self, style: Style) -> Self {
self.gauge_style = style;
pub fn gauge_style<S: Into<Style>>(mut self, style: S) -> Self {
self.gauge_style = style.into();
self
}
}
@ -406,7 +418,7 @@ impl<'a> Styled for Gauge<'a> {
self.style
}
fn set_style(self, style: Style) -> Self::Item {
fn set_style<S: Into<Style>>(self, style: S) -> Self::Item {
self.style(style)
}
}
@ -418,7 +430,7 @@ impl<'a> Styled for LineGauge<'a> {
self.style
}
fn set_style(self, style: Style) -> Self::Item {
fn set_style<S: Into<Style>>(self, style: S) -> Self::Item {
self.style(style)
}
}

View File

@ -3,10 +3,7 @@ use strum::{Display, EnumString};
use unicode_width::UnicodeWidthStr;
use crate::{
buffer::Buffer,
layout::{Alignment, Corner, Rect},
style::{Style, Styled},
text::Text,
prelude::*,
widgets::{Block, HighlightSpacing, StatefulWidget, Widget},
};
@ -256,6 +253,9 @@ impl<'a> ListItem<'a> {
/// Sets the item style
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// This [`Style`] can be overridden by the [`Style`] of the [`Text`] content.
///
/// This is a fluent setter method which must be chained or used as it consumes self
@ -276,8 +276,8 @@ impl<'a> ListItem<'a> {
/// let item = ListItem::new("Item 1").red().italic();
/// ```
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style(mut self, style: Style) -> ListItem<'a> {
self.style = style;
pub fn style<S: Into<Style>>(mut self, style: S) -> ListItem<'a> {
self.style = style.into();
self
}
@ -523,6 +523,9 @@ impl<'a> List<'a> {
/// Sets the base style of the widget
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// All text rendered by the widget will use this style, unless overridden by [`Block::style`],
/// [`ListItem::style`], or the styles of the [`ListItem`]'s content.
///
@ -547,8 +550,8 @@ impl<'a> List<'a> {
/// let list = List::new(items).red().italic();
/// ```
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style(mut self, style: Style) -> List<'a> {
self.style = style;
pub fn style<S: Into<Style>>(mut self, style: S) -> List<'a> {
self.style = style.into();
self
}
@ -573,6 +576,9 @@ impl<'a> List<'a> {
/// Set the style of the selected item
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// This style will be applied to the entire item, including the
/// [highlight symbol](List::highlight_symbol) if it is displayed, and will override any style
/// set on the item or on the individual cells.
@ -587,8 +593,8 @@ impl<'a> List<'a> {
/// let list = List::new(items).highlight_style(Style::new().red().italic());
/// ```
#[must_use = "method moves the value of self and returns the modified value"]
pub fn highlight_style(mut self, style: Style) -> List<'a> {
self.highlight_style = style;
pub fn highlight_style<S: Into<Style>>(mut self, style: S) -> List<'a> {
self.highlight_style = style.into();
self
}
@ -854,7 +860,7 @@ impl<'a> Styled for List<'a> {
self.style
}
fn set_style(self, style: Style) -> Self::Item {
fn set_style<S: Into<Style>>(self, style: S) -> Self::Item {
self.style(style)
}
}
@ -866,7 +872,7 @@ impl<'a> Styled for ListItem<'a> {
self.style
}
fn set_style(self, style: Style) -> Self::Item {
fn set_style<S: Into<Style>>(self, style: S) -> Self::Item {
self.style(style)
}
}

View File

@ -1,10 +1,8 @@
use unicode_width::UnicodeWidthStr;
use crate::{
buffer::Buffer,
layout::{Alignment, Rect},
style::{Style, Styled},
text::{StyledGrapheme, Text},
prelude::*,
text::StyledGrapheme,
widgets::{
reflow::{LineComposer, LineTruncator, WordWrapper, WrappedLine},
Block, Widget,
@ -142,6 +140,9 @@ impl<'a> Paragraph<'a> {
/// Sets the style of the entire widget.
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// This applies to the entire widget, including the block if one is present. Any style set on
/// the block or text will be added to this style.
///
@ -152,8 +153,8 @@ impl<'a> Paragraph<'a> {
/// let paragraph = Paragraph::new("Hello, world!").style(Style::new().red().on_white());
/// ```
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style(mut self, style: Style) -> Paragraph<'a> {
self.style = style;
pub fn style<S: Into<Style>>(mut self, style: S) -> Paragraph<'a> {
self.style = style.into();
self
}
@ -355,7 +356,7 @@ impl<'a> Styled for Paragraph<'a> {
self.style
}
fn set_style(self, style: Style) -> Self::Item {
fn set_style<S: Into<Style>>(self, style: S) -> Self::Item {
self.style(style)
}
}

View File

@ -2,9 +2,7 @@ use strum::{Display, EnumString};
use super::StatefulWidget;
use crate::{
buffer::Buffer,
layout::Rect,
style::Style,
prelude::*,
symbols::scrollbar::{Set, DOUBLE_HORIZONTAL, DOUBLE_VERTICAL},
};
@ -239,9 +237,12 @@ impl<'a> Scrollbar<'a> {
}
/// Sets the style that represents the thumb of the scrollbar.
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
#[must_use = "method moves the value of self and returns the modified value"]
pub fn thumb_style(mut self, thumb_style: Style) -> Self {
self.thumb_style = thumb_style;
pub fn thumb_style<S: Into<Style>>(mut self, thumb_style: S) -> Self {
self.thumb_style = thumb_style.into();
self
}
@ -253,9 +254,12 @@ impl<'a> Scrollbar<'a> {
}
/// Sets the style that is used for the track of the scrollbar.
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
#[must_use = "method moves the value of self and returns the modified value"]
pub fn track_style(mut self, track_style: Style) -> Self {
self.track_style = track_style;
pub fn track_style<S: Into<Style>>(mut self, track_style: S) -> Self {
self.track_style = track_style.into();
self
}
@ -267,9 +271,12 @@ impl<'a> Scrollbar<'a> {
}
/// Sets the style that is used for the beginning of the scrollbar.
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
#[must_use = "method moves the value of self and returns the modified value"]
pub fn begin_style(mut self, begin_style: Style) -> Self {
self.begin_style = begin_style;
pub fn begin_style<S: Into<Style>>(mut self, begin_style: S) -> Self {
self.begin_style = begin_style.into();
self
}
@ -281,9 +288,12 @@ impl<'a> Scrollbar<'a> {
}
/// Sets the style that is used for the end of the scrollbar.
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
#[must_use = "method moves the value of self and returns the modified value"]
pub fn end_style(mut self, end_style: Style) -> Self {
self.end_style = end_style;
pub fn end_style<S: Into<Style>>(mut self, end_style: S) -> Self {
self.end_style = end_style.into();
self
}
@ -316,6 +326,10 @@ impl<'a> Scrollbar<'a> {
}
/// Sets the style used for the various parts of the scrollbar from a [`Style`].
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// ```text
/// <--▮------->
/// ^ ^ ^ ^
@ -325,7 +339,8 @@ impl<'a> Scrollbar<'a> {
/// └─────────── begin
/// ```
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style(mut self, style: Style) -> Self {
pub fn style<S: Into<Style>>(mut self, style: S) -> Self {
let style = style.into();
self.track_style = style;
self.thumb_style = style;
self.begin_style = style;

View File

@ -4,10 +4,7 @@ use std::cmp::min;
use strum::{Display, EnumString};
use crate::{
buffer::Buffer,
layout::Rect,
style::{Style, Styled},
symbols,
prelude::*,
widgets::{Block, Widget},
};
@ -89,10 +86,13 @@ impl<'a> Sparkline<'a> {
/// Sets the style of the entire widget.
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// The foreground corresponds to the bars while the background is everything else.
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style(mut self, style: Style) -> Sparkline<'a> {
self.style = style;
pub fn style<S: Into<Style>>(mut self, style: S) -> Sparkline<'a> {
self.style = style.into();
self
}
@ -151,7 +151,7 @@ impl<'a> Styled for Sparkline<'a> {
self.style
}
fn set_style(self, style: Style) -> Self::Item {
fn set_style<S: Into<Style>>(self, style: S) -> Self::Item {
self.style(style)
}
}

View File

@ -98,6 +98,9 @@ impl<'a> Cell<'a> {
/// Set the `Style` of this cell
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// This `Style` will override the `Style` of the [`Row`] and can be overridden by the `Style`
/// of the [`Text`] content.
///
@ -120,8 +123,8 @@ impl<'a> Cell<'a> {
///
/// [`Row`]: super::Row
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style(mut self, style: Style) -> Self {
self.style = style;
pub fn style<S: Into<Style>>(mut self, style: S) -> Self {
self.style = style.into();
self
}
}
@ -169,7 +172,7 @@ impl<'a> Styled for Cell<'a> {
self.style
}
fn set_style(self, style: Style) -> Self::Item {
fn set_style<S: Into<Style>>(self, style: S) -> Self::Item {
self.style(style)
}
}

View File

@ -182,6 +182,9 @@ impl<'a> Row<'a> {
/// Set the [`Style`] of the entire row
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// This [`Style`] can be overridden by the [`Style`] of a any individual [`Cell`] or by their
/// [`Text`] content.
///
@ -204,8 +207,8 @@ impl<'a> Row<'a> {
/// let row = Row::new(cells).red().italic();
/// ```
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style(mut self, style: Style) -> Self {
self.style = style;
pub fn style<S: Into<Style>>(mut self, style: S) -> Self {
self.style = style.into();
self
}
}
@ -227,7 +230,7 @@ impl<'a> Styled for Row<'a> {
self.style
}
fn set_style(self, style: Style) -> Self::Item {
fn set_style<S: Into<Style>>(self, style: S) -> Self::Item {
self.style(style)
}
}

View File

@ -396,6 +396,9 @@ impl<'a> Table<'a> {
/// Sets the base style of the widget
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// All text rendered by the widget will use this style, unless overridden by [`Block::style`],
/// [`Row::style`], [`Cell::style`], or the styles of cell's content.
///
@ -420,13 +423,16 @@ impl<'a> Table<'a> {
/// let table = Table::new(rows, widths).red().italic();
/// ```
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style(mut self, style: Style) -> Self {
self.style = style;
pub fn style<S: Into<Style>>(mut self, style: S) -> Self {
self.style = style.into();
self
}
/// Set the style of the selected row
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// This style will be applied to the entire row, including the selection symbol if it is
/// displayed, and will override any style set on the row or on the individual cells.
///
@ -441,8 +447,8 @@ impl<'a> Table<'a> {
/// let table = Table::new(rows, widths).highlight_style(Style::new().red().italic());
/// ```
#[must_use = "method moves the value of self and returns the modified value"]
pub fn highlight_style(mut self, highlight_style: Style) -> Self {
self.highlight_style = highlight_style;
pub fn highlight_style<S: Into<Style>>(mut self, highlight_style: S) -> Self {
self.highlight_style = highlight_style.into();
self
}
@ -788,7 +794,7 @@ impl<'a> Styled for Table<'a> {
self.style
}
fn set_style(self, style: Style) -> Self::Item {
fn set_style<S: Into<Style>>(self, style: S) -> Self::Item {
self.style(style)
}
}

View File

@ -1,10 +1,6 @@
#![deny(missing_docs)]
use crate::{
buffer::Buffer,
layout::Rect,
style::{Modifier, Style, Styled},
symbols,
text::{Line, Span},
prelude::*,
widgets::{Block, Widget},
};
@ -118,21 +114,27 @@ impl<'a> Tabs<'a> {
/// Sets the style of the tabs.
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// This will set the given style on the entire render area.
/// More precise style can be applied to the titles by styling the ones given to [`Tabs::new`].
/// The selected tab can be styled differently using [`Tabs::highlight_style`].
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style(mut self, style: Style) -> Tabs<'a> {
self.style = style;
pub fn style<S: Into<Style>>(mut self, style: S) -> Self {
self.style = style.into();
self
}
/// Sets the style for the highlighted tab.
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// Highlighted tab can be selected with [`Tabs::select`].
#[must_use = "method moves the value of self and returns the modified value"]
pub fn highlight_style(mut self, style: Style) -> Tabs<'a> {
self.highlight_style = style;
pub fn highlight_style<S: Into<Style>>(mut self, style: S) -> Tabs<'a> {
self.highlight_style = style.into();
self
}
@ -232,7 +234,7 @@ impl<'a> Styled for Tabs<'a> {
self.style
}
fn set_style(self, style: Style) -> Self::Item {
fn set_style<S: Into<Style>>(self, style: S) -> Self::Item {
self.style(style)
}
}
@ -307,7 +309,7 @@ impl<'a> Widget for Tabs<'a> {
#[cfg(test)]
mod tests {
use super::*;
use crate::{assert_buffer_eq, prelude::*, widgets::Borders};
use crate::{assert_buffer_eq, widgets::Borders};
#[test]
fn new() {