mirror of
https://github.com/ratatui-org/ratatui
synced 2024-11-25 14:10:31 +00:00
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:
parent
4278b4088d
commit
2a12f7bddf
3 changed files with 53 additions and 45 deletions
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue