From 369b18eef2e4220147e7c7264ad7f8e023a1d2dd Mon Sep 17 00:00:00 2001 From: Emirhan TALA Date: Sun, 24 Nov 2024 11:06:16 +0300 Subject: [PATCH] feat(barchart): reduce barchart creation verbosity (#1453) Adds constructor methods for BarChart, BarGroup, and Bar --- ratatui-widgets/src/barchart.rs | 81 ++++++++++++++++++++++- ratatui-widgets/src/barchart/bar.rs | 62 +++++++++++++++-- ratatui-widgets/src/barchart/bar_group.rs | 38 +++++++++-- 3 files changed, 169 insertions(+), 12 deletions(-) diff --git a/ratatui-widgets/src/barchart.rs b/ratatui-widgets/src/barchart.rs index aa6f92a5..93c68a74 100644 --- a/ratatui-widgets/src/barchart.rs +++ b/ratatui-widgets/src/barchart.rs @@ -64,10 +64,21 @@ mod bar_group; /// .bar_style(Style::new().yellow().on_red()) /// .value_style(Style::new().red().bold()) /// .label_style(Style::new().white()) -/// .data(&[("B0", 0), ("B1", 2), ("B2", 4), ("B3", 3)]) -/// .data(BarGroup::default().bars(&[Bar::default().value(10), Bar::default().value(20)])) +/// .data(&[("A0", 0), ("A1", 2), ("A2", 4), ("A3", 3)]) +/// .data(BarGroup::new([ +/// Bar::with_label("B0", 10), +/// Bar::with_label("B2", 20), +/// ])) /// .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)] pub struct BarChart<'a> { /// Block to wrap the widget in @@ -117,6 +128,52 @@ impl<'a> Default for 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`. + /// + /// # 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>>>(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>>) -> 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>>) -> Self { + Self { + data: vec![BarGroup::new(bars.into())], + direction: Direction::Horizontal, + ..Default::default() + } + } + /// Add group of bars to the `BarChart` /// /// # Examples @@ -129,7 +186,10 @@ impl<'a> BarChart<'a> { /// /// BarChart::default() /// .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"] pub fn data(mut self, data: impl Into>) -> Self { @@ -1345,4 +1405,19 @@ mod tests { ]); 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)]); + } } diff --git a/ratatui-widgets/src/barchart/bar.rs b/ratatui-widgets/src/barchart/bar.rs index 782b1256..bded82f3 100644 --- a/ratatui-widgets/src/barchart/bar.rs +++ b/ratatui-widgets/src/barchart/bar.rs @@ -27,9 +27,7 @@ use unicode_width::UnicodeWidthStr; /// widgets::Bar, /// }; /// -/// Bar::default() -/// .label("Bar 1") -/// .value(10) +/// Bar::with_label("Bar 1", 10) /// .red() /// .value_style(Style::new().red().on_white()) /// .text_value("10°C"); @@ -49,14 +47,54 @@ pub struct 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>>(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. /// /// The value will be displayed inside the bar. /// /// # See also /// - /// [`Bar::value_style`] to style the value. - /// [`Bar::text_value`] to set the displayed value. + /// - [`Bar::value_style`] to style the value. + /// - [`Bar::text_value`] to set the displayed value. #[must_use = "method moves the value of self and returns the modified value"] pub const fn value(mut self, value: u64) -> Self { self.value = value; @@ -266,6 +304,20 @@ mod tests { 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] fn test_bar_stylized() { let bar = Bar::default().red().bold(); diff --git a/ratatui-widgets/src/barchart/bar_group.rs b/ratatui-widgets/src/barchart/bar_group.rs index ede07aac..43705123 100644 --- a/ratatui-widgets/src/barchart/bar_group.rs +++ b/ratatui-widgets/src/barchart/bar_group.rs @@ -15,9 +15,7 @@ use crate::barchart::Bar; /// ``` /// use ratatui::widgets::{Bar, BarGroup}; /// -/// BarGroup::default() -/// .label("Group 1") -/// .bars(&[Bar::default().value(200), Bar::default().value(150)]); +/// let group = BarGroup::new([Bar::with_label("Red", 20), Bar::with_label("Blue", 15)]); /// ``` #[derive(Debug, Default, Clone, Eq, PartialEq, Hash)] pub struct BarGroup<'a> { @@ -28,6 +26,25 @@ pub struct 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>>>(bars: T) -> Self { + Self { + bars: bars.into(), + ..Self::default() + } + } + /// Set the group label /// /// `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, bars: value .iter() - .map(|&(text, v)| Bar::default().value(v).label(text)) + .map(|&(text, v)| Bar::with_label(text, v)) .collect(), } } @@ -117,3 +134,16 @@ impl<'a> From<&Vec<(&'a str, u64)>> for BarGroup<'a> { 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); + } +}