feat(barchart): reduce barchart creation verbosity (#1453)

Adds constructor methods for BarChart, BarGroup, and Bar
This commit is contained in:
Emirhan TALA 2024-11-24 11:06:16 +03:00 committed by GitHub
parent 2ce958e38c
commit 369b18eef2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 169 additions and 12 deletions

View File

@ -64,10 +64,21 @@ mod bar_group;
/// .bar_style(Style::new().yellow().on_red()) /// .bar_style(Style::new().yellow().on_red())
/// .value_style(Style::new().red().bold()) /// .value_style(Style::new().red().bold())
/// .label_style(Style::new().white()) /// .label_style(Style::new().white())
/// .data(&[("B0", 0), ("B1", 2), ("B2", 4), ("B3", 3)]) /// .data(&[("A0", 0), ("A1", 2), ("A2", 4), ("A3", 3)])
/// .data(BarGroup::default().bars(&[Bar::default().value(10), Bar::default().value(20)])) /// .data(BarGroup::new([
/// Bar::with_label("B0", 10),
/// Bar::with_label("B2", 20),
/// ]))
/// .max(4); /// .max(4);
/// ``` /// ```
///
/// For simpler usages, you can also create a `BarChart` simply by
///
/// ```rust
/// use ratatui::widgets::{Bar, BarChart};
///
/// BarChart::new([Bar::with_label("A", 10), Bar::with_label("B", 20)]);
/// ```
#[derive(Debug, Clone, Eq, PartialEq, Hash)] #[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct BarChart<'a> { pub struct BarChart<'a> {
/// Block to wrap the widget in /// Block to wrap the widget in
@ -117,6 +128,52 @@ impl<'a> Default for BarChart<'a> {
} }
impl<'a> BarChart<'a> { impl<'a> BarChart<'a> {
/// Creates a new vertical `BarChart` widget with the given bars.
///
/// The `bars` parameter accepts any type that can be converted into a `Vec<Bar>`.
///
/// # Examples
///
/// ```rust
/// use ratatui::{
/// layout::Direction,
/// widgets::{Bar, BarChart},
/// };
///
/// BarChart::new(vec![Bar::with_label("A", 10), Bar::with_label("B", 10)]);
/// ```
pub fn new<T: Into<Vec<Bar<'a>>>>(bars: T) -> Self {
Self {
data: vec![BarGroup::new(bars.into())],
direction: Direction::Vertical,
..Default::default()
}
}
/// Creates a new `BarChart` widget with a vertical direction.
///
/// This function is equivalent to `BarChart::new()`.
pub fn vertical(bars: impl Into<Vec<Bar<'a>>>) -> Self {
Self::new(bars)
}
/// Creates a new `BarChart` widget with a horizontal direction.
///
/// # Examples
///
/// ```rust
/// use ratatui::widgets::{Bar, BarChart};
///
/// BarChart::horizontal(vec![Bar::with_label("A", 10), Bar::with_label("B", 20)]);
/// ```
pub fn horizontal(bars: impl Into<Vec<Bar<'a>>>) -> Self {
Self {
data: vec![BarGroup::new(bars.into())],
direction: Direction::Horizontal,
..Default::default()
}
}
/// Add group of bars to the `BarChart` /// Add group of bars to the `BarChart`
/// ///
/// # Examples /// # Examples
@ -129,7 +186,10 @@ impl<'a> BarChart<'a> {
/// ///
/// BarChart::default() /// BarChart::default()
/// .data(&[("B0", 0), ("B1", 2), ("B2", 4), ("B3", 3)]) /// .data(&[("B0", 0), ("B1", 2), ("B2", 4), ("B3", 3)])
/// .data(BarGroup::default().bars(&[Bar::default().value(10), Bar::default().value(20)])); /// .data(BarGroup::new([
/// Bar::with_label("A", 10),
/// Bar::with_label("B", 20),
/// ]));
/// ``` /// ```
#[must_use = "method moves the value of self and returns the modified value"] #[must_use = "method moves the value of self and returns the modified value"]
pub fn data(mut self, data: impl Into<BarGroup<'a>>) -> Self { pub fn data(mut self, data: impl Into<BarGroup<'a>>) -> Self {
@ -1345,4 +1405,19 @@ mod tests {
]); ]);
assert_eq!(buffer, expected); assert_eq!(buffer, expected);
} }
#[test]
fn test_barchart_new() {
let bars = [Bar::with_label("Red", 1), Bar::with_label("Green", 2)];
let chart = BarChart::new(bars.clone());
assert_eq!(chart.data.len(), 1);
assert_eq!(chart.data[0].bars, bars);
let bars2 = [("Blue", 3)];
let updated_chart = chart.data(&bars2);
assert_eq!(updated_chart.data.len(), 2);
assert_eq!(updated_chart.data[1].bars, [Bar::with_label("Blue", 3)]);
}
} }

View File

@ -27,9 +27,7 @@ use unicode_width::UnicodeWidthStr;
/// widgets::Bar, /// widgets::Bar,
/// }; /// };
/// ///
/// Bar::default() /// Bar::with_label("Bar 1", 10)
/// .label("Bar 1")
/// .value(10)
/// .red() /// .red()
/// .value_style(Style::new().red().on_white()) /// .value_style(Style::new().red().on_white())
/// .text_value("10°C"); /// .text_value("10°C");
@ -49,14 +47,54 @@ pub struct Bar<'a> {
} }
impl<'a> Bar<'a> { impl<'a> Bar<'a> {
/// Creates a new `Bar` with the given value.
///
/// # Examples
///
/// ```
/// use ratatui::widgets::Bar;
///
/// let bar = Bar::new(42);
/// ```
pub const fn new(value: u64) -> Self {
Self {
value,
label: None,
style: Style::new(),
value_style: Style::new(),
text_value: None,
}
}
/// Creates a new `Bar` with the given `label` and value.
///
/// a `label` can be a [`&str`], [`String`] or anything that can be converted into [`Line`].
///
/// # Examples
///
/// ```
/// use ratatui::widgets::Bar;
///
/// let bar = Bar::with_label("Label", 42);
/// ```
pub fn with_label<T: Into<Line<'a>>>(label: T, value: u64) -> Self {
Self {
value,
label: Some(label.into()),
style: Style::new(),
value_style: Style::new(),
text_value: None,
}
}
/// Set the value of this bar. /// Set the value of this bar.
/// ///
/// The value will be displayed inside the bar. /// The value will be displayed inside the bar.
/// ///
/// # See also /// # See also
/// ///
/// [`Bar::value_style`] to style the value. /// - [`Bar::value_style`] to style the value.
/// [`Bar::text_value`] to set the displayed value. /// - [`Bar::text_value`] to set the displayed value.
#[must_use = "method moves the value of self and returns the modified value"] #[must_use = "method moves the value of self and returns the modified value"]
pub const fn value(mut self, value: u64) -> Self { pub const fn value(mut self, value: u64) -> Self {
self.value = value; self.value = value;
@ -266,6 +304,20 @@ mod tests {
use super::*; use super::*;
#[test]
fn test_bar_new() {
let bar = Bar::new(42).label(Line::from("Label"));
assert_eq!(bar.label, Some(Line::from("Label")));
assert_eq!(bar.value, 42);
}
#[test]
fn test_bar_with_label() {
let bar = Bar::with_label("Label", 42);
assert_eq!(bar.label, Some(Line::from("Label")));
assert_eq!(bar.value, 42);
}
#[test] #[test]
fn test_bar_stylized() { fn test_bar_stylized() {
let bar = Bar::default().red().bold(); let bar = Bar::default().red().bold();

View File

@ -15,9 +15,7 @@ use crate::barchart::Bar;
/// ``` /// ```
/// use ratatui::widgets::{Bar, BarGroup}; /// use ratatui::widgets::{Bar, BarGroup};
/// ///
/// BarGroup::default() /// let group = BarGroup::new([Bar::with_label("Red", 20), Bar::with_label("Blue", 15)]);
/// .label("Group 1")
/// .bars(&[Bar::default().value(200), Bar::default().value(150)]);
/// ``` /// ```
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)] #[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
pub struct BarGroup<'a> { pub struct BarGroup<'a> {
@ -28,6 +26,25 @@ pub struct BarGroup<'a> {
} }
impl<'a> BarGroup<'a> { impl<'a> BarGroup<'a> {
/// Creates a new `BarGroup` with the given bars.
///
/// # Examples
///
/// ```
/// use ratatui::{
/// style::{Style, Stylize},
/// widgets::{Bar, BarGroup},
/// };
///
/// let group = BarGroup::new(vec![Bar::with_label("A", 10), Bar::with_label("B", 20)]);
/// ```
pub fn new<T: Into<Vec<Bar<'a>>>>(bars: T) -> Self {
Self {
bars: bars.into(),
..Self::default()
}
}
/// Set the group label /// Set the group label
/// ///
/// `label` can be a [`&str`], [`String`] or anything that can be converted into [`Line`]. /// `label` can be a [`&str`], [`String`] or anything that can be converted into [`Line`].
@ -98,7 +115,7 @@ impl<'a> From<&[(&'a str, u64)]> for BarGroup<'a> {
label: None, label: None,
bars: value bars: value
.iter() .iter()
.map(|&(text, v)| Bar::default().value(v).label(text)) .map(|&(text, v)| Bar::with_label(text, v))
.collect(), .collect(),
} }
} }
@ -117,3 +134,16 @@ impl<'a> From<&Vec<(&'a str, u64)>> for BarGroup<'a> {
Self::from(array) Self::from(array)
} }
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bargroup_new() {
let group = BarGroup::new([Bar::with_label("Label1", 1), Bar::with_label("Label2", 2)])
.label(Line::from("Group1"));
assert_eq!(group.label, Some(Line::from("Group1")));
assert_eq!(group.bars.len(), 2);
}
}