ratatui_widgets/barchart/
bar_group.rs1use alloc::vec::Vec;
2
3use ratatui_core::buffer::Buffer;
4use ratatui_core::layout::{Alignment, Rect};
5use ratatui_core::style::Style;
6use ratatui_core::text::Line;
7use ratatui_core::widgets::Widget;
8
9use crate::barchart::Bar;
10
11#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
21pub struct BarGroup<'a> {
22 pub(super) label: Option<Line<'a>>,
24 pub(super) bars: Vec<Bar<'a>>,
26}
27
28impl<'a> BarGroup<'a> {
29 pub fn new<T: Into<Vec<Bar<'a>>>>(bars: T) -> Self {
40 Self {
41 bars: bars.into(),
42 ..Self::default()
43 }
44 }
45
46 pub fn with_label<T: Into<Line<'a>>, B: Into<Vec<Bar<'a>>>>(label: T, bars: B) -> Self {
60 Self {
61 label: Some(label.into()),
62 bars: bars.into(),
63 }
64 }
65
66 #[must_use = "method moves the value of self and returns the modified value"]
92 pub fn label<T: Into<Line<'a>>>(mut self, label: T) -> Self {
93 self.label = Some(label.into());
94 self
95 }
96
97 #[must_use = "method moves the value of self and returns the modified value"]
99 pub fn bars(mut self, bars: &[Bar<'a>]) -> Self {
100 self.bars = bars.to_vec();
101 self
102 }
103
104 pub(super) fn max(&self) -> Option<u64> {
106 self.bars.iter().max_by_key(|v| v.value).map(|v| v.value)
107 }
108
109 pub(super) fn render_label(&self, buf: &mut Buffer, area: Rect, default_label_style: Style) {
110 if let Some(label) = &self.label {
111 let width = label.width() as u16;
114 let area = match label.alignment {
115 Some(Alignment::Center) => Rect {
116 x: area.x + (area.width.saturating_sub(width)) / 2,
117 width,
118 ..area
119 },
120 Some(Alignment::Right) => Rect {
121 x: area.x + area.width.saturating_sub(width),
122 width,
123 ..area
124 },
125 _ => Rect { width, ..area },
126 };
127 buf.set_style(area, default_label_style);
128 label.render(area, buf);
129 }
130 }
131}
132
133impl<'a> From<&[(&'a str, u64)]> for BarGroup<'a> {
134 fn from(value: &[(&'a str, u64)]) -> Self {
135 Self {
136 label: None,
137 bars: value
138 .iter()
139 .map(|&(text, v)| Bar::with_label(text, v))
140 .collect(),
141 }
142 }
143}
144
145impl<'a, const N: usize> From<&[(&'a str, u64); N]> for BarGroup<'a> {
146 fn from(value: &[(&'a str, u64); N]) -> Self {
147 let value: &[(&'a str, u64)] = value.as_ref();
148 Self::from(value)
149 }
150}
151
152impl<'a> From<&Vec<(&'a str, u64)>> for BarGroup<'a> {
153 fn from(value: &Vec<(&'a str, u64)>) -> Self {
154 let array: &[(&str, u64)] = value;
155 Self::from(array)
156 }
157}
158
159#[cfg(test)]
160mod tests {
161 use super::*;
162
163 #[test]
164 fn test_bargroup_new() {
165 let group = BarGroup::new([Bar::with_label("Label1", 1), Bar::with_label("Label2", 2)])
166 .label(Line::from("Group1"));
167 assert_eq!(group.label, Some(Line::from("Group1")));
168 assert_eq!(group.bars.len(), 2);
169 }
170}