feat: impl Widget for &BarChart (#897)

BarChart had some internal mutations that needed to be removed to
implement the Widget trait for &BarChart to bring it in line with the
other widgets.
This commit is contained in:
Josh McKinney 2024-01-31 11:21:32 -08:00 committed by GitHub
parent 4278b4088d
commit 2a12f7bddf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 53 additions and 45 deletions

View file

@ -313,7 +313,7 @@ struct LabelInfo {
height: u16,
}
impl<'a> BarChart<'a> {
impl BarChart<'_> {
/// Returns the visible bars length in ticks. A cell contains 8 ticks.
/// `available_space` used to calculate how many bars can fit in the space
/// `bar_max_length` is the maximal length a bar can take.
@ -392,7 +392,7 @@ impl<'a> BarChart<'a> {
}
}
fn render_horizontal(self, buf: &mut Buffer, area: Rect) {
fn render_horizontal(&self, buf: &mut Buffer, area: Rect) {
// get the longest label
let label_size = self
.data
@ -417,10 +417,8 @@ impl<'a> BarChart<'a> {
// print all visible bars, label and values
let mut bar_y = bars_area.top();
for (ticks_vec, mut group) in group_ticks.into_iter().zip(self.data) {
let bars = std::mem::take(&mut group.bars);
for (ticks, bar) in ticks_vec.into_iter().zip(bars) {
for (ticks_vec, group) in group_ticks.into_iter().zip(self.data.iter()) {
for (ticks, bar) in ticks_vec.into_iter().zip(group.bars.iter()) {
let bar_length = (ticks / 8) as u16;
let bar_style = self.bar_style.patch(bar.style);
@ -473,7 +471,7 @@ impl<'a> BarChart<'a> {
}
}
fn render_vertical(self, buf: &mut Buffer, area: Rect) {
fn render_vertical(&self, buf: &mut Buffer, area: Rect) {
let label_info = self.label_info(area.height - 1);
let bars_area = Rect {
@ -535,7 +533,7 @@ impl<'a> BarChart<'a> {
}
fn render_labels_and_values(
self,
&self,
area: Rect,
buf: &mut Buffer,
label_info: LabelInfo,
@ -544,12 +542,10 @@ impl<'a> BarChart<'a> {
// print labels and values in one go
let mut bar_x = area.left();
let bar_y = area.bottom() - label_info.height - 1;
for (mut group, ticks_vec) in self.data.into_iter().zip(group_ticks) {
for (group, ticks_vec) in self.data.iter().zip(group_ticks) {
if group.bars.is_empty() {
continue;
}
let bars = std::mem::take(&mut group.bars);
// print group labels under the bars or the previous labels
if label_info.group_label_visible {
let label_max_width =
@ -564,7 +560,7 @@ impl<'a> BarChart<'a> {
}
// print the bar values and numbers
for (mut bar, ticks) in bars.into_iter().zip(ticks_vec) {
for (bar, ticks) in group.bars.iter().zip(ticks_vec) {
if label_info.bar_label_visible {
bar.render_label(buf, self.bar_width, bar_x, bar_y + 1, self.label_style);
}
@ -579,6 +575,12 @@ impl<'a> BarChart<'a> {
}
impl Widget for BarChart<'_> {
fn render(self, area: Rect, buf: &mut Buffer) {
(&self).render(area, buf);
}
}
impl Widget for &BarChart<'_> {
fn render(self, area: Rect, buf: &mut Buffer) {
buf.set_style(area, self.style);

View file

@ -147,7 +147,7 @@ impl<'a> Bar<'a> {
}
pub(super) fn render_value(
self,
&self,
buf: &mut Buffer,
max_width: u16,
x: u16,
@ -156,12 +156,8 @@ impl<'a> Bar<'a> {
ticks: u64,
) {
if self.value != 0 {
let value_label = if let Some(text) = self.text_value {
text
} else {
self.value.to_string()
};
let value = self.value.to_string();
let value_label = self.text_value.as_ref().unwrap_or(&value);
let width = value_label.width() as u16;
const TICKS_PER_LINE: u64 = 8;
// if we have enough space or the ticks are greater equal than 1 cell (8)
@ -178,25 +174,29 @@ impl<'a> Bar<'a> {
}
pub(super) fn render_label(
&mut self,
&self,
buf: &mut Buffer,
max_width: u16,
x: u16,
y: u16,
default_label_style: Style,
) {
if let Some(label) = &mut self.label {
// patch label styles
for span in &mut label.spans {
span.style = default_label_style.patch(span.style);
}
buf.set_line(
x + (max_width.saturating_sub(label.width() as u16) >> 1),
y,
label,
max_width,
);
// center the label. Necessary to do it this way as we don't want to set the style
// of the whole area, just the label area
let width = self
.label
.as_ref()
.map_or(0, Line::width)
.min(max_width as usize) as u16;
let area = Rect {
x: x + (max_width.saturating_sub(width)) / 2,
y,
width,
height: 1,
};
buf.set_style(area, default_label_style);
if let Some(label) = &self.label {
label.render(area, buf);
}
}
}

View file

@ -40,20 +40,26 @@ impl<'a> BarGroup<'a> {
self.bars.iter().max_by_key(|v| v.value).map(|v| v.value)
}
pub(super) fn render_label(self, buf: &mut Buffer, area: Rect, default_label_style: Style) {
if let Some(mut label) = self.label {
// patch label styles
for span in &mut label.spans {
span.style = default_label_style.patch(span.style);
}
let x_offset = match label.alignment {
Some(Alignment::Center) => area.width.saturating_sub(label.width() as u16) >> 1,
Some(Alignment::Right) => area.width.saturating_sub(label.width() as u16),
_ => 0,
pub(super) fn render_label(&self, buf: &mut Buffer, area: Rect, default_label_style: Style) {
if let Some(label) = &self.label {
// align the label. Necessary to do it this way as we don't want to set the style
// of the whole area, just the label area
let width = label.width() as u16;
let area = match label.alignment {
Some(Alignment::Center) => Rect {
x: area.x + (area.width.saturating_sub(width)) / 2,
width,
..area
},
Some(Alignment::Right) => Rect {
x: area.x + area.width.saturating_sub(width),
width,
..area
},
_ => Rect { width, ..area },
};
buf.set_line(area.x + x_offset, area.y, &label, area.width);
buf.set_style(area, default_label_style);
label.render(area, buf);
}
}
}