mirror of
https://github.com/ClementTsang/bottom.git
synced 2025-04-08 17:05:59 +02:00
refactor: per-row styling, remove seemingly redundant table code
This commit is contained in:
parent
2e51590bf5
commit
df1a418327
@ -7,6 +7,7 @@ use tui::widgets::TableState;
|
||||
use crate::{
|
||||
app::{layout_manager::BottomWidgetType, query::*},
|
||||
constants,
|
||||
data_conversion::CellContent,
|
||||
data_harvester::processes::{self, ProcessSorting},
|
||||
};
|
||||
use ProcessSorting::*;
|
||||
@ -70,10 +71,7 @@ impl WidthBounds {
|
||||
|
||||
pub struct TableComponentColumn {
|
||||
/// The name of the column. Displayed if possible as the header.
|
||||
pub name: Cow<'static, str>,
|
||||
|
||||
/// An optional alternative column name. Displayed if `name` doesn't fit.
|
||||
pub alt: Option<Cow<'static, str>>,
|
||||
pub name: CellContent,
|
||||
|
||||
/// A restriction on this column's width, if desired.
|
||||
pub width_bounds: WidthBounds,
|
||||
@ -85,8 +83,14 @@ impl TableComponentColumn {
|
||||
I: Into<Cow<'static, str>>,
|
||||
{
|
||||
Self {
|
||||
name: name.into(),
|
||||
alt: alt.map(Into::into),
|
||||
name: if let Some(alt) = alt {
|
||||
CellContent::HasAlt {
|
||||
alt: alt.into(),
|
||||
main: name.into(),
|
||||
}
|
||||
} else {
|
||||
CellContent::Simple(name.into())
|
||||
},
|
||||
width_bounds,
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ use unicode_segmentation::UnicodeSegmentation;
|
||||
use crate::{
|
||||
app::{self, TableComponentState},
|
||||
constants::{SIDE_BORDERS, TABLE_GAP_HEIGHT_LIMIT},
|
||||
data_conversion::{CellContent, TableData},
|
||||
data_conversion::{CellContent, TableData, TableRow},
|
||||
};
|
||||
|
||||
pub struct TextTable<'a> {
|
||||
@ -98,14 +98,12 @@ impl<'a> TextTable<'a> {
|
||||
pub fn draw_text_table<B: Backend>(
|
||||
&self, f: &mut Frame<'_, B>, draw_loc: Rect, state: &mut TableComponentState,
|
||||
table_data: &TableData,
|
||||
) -> Rect {
|
||||
) {
|
||||
// TODO: This is a *really* ugly hack to get basic mode to hide the border when not selected, without shifting everything.
|
||||
let is_not_basic = self.is_on_widget || self.draw_border;
|
||||
let margined_draw_loc = Layout::default()
|
||||
.constraints([Constraint::Percentage(100)])
|
||||
.horizontal_margin(if self.is_on_widget || self.draw_border {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
})
|
||||
.horizontal_margin(if is_not_basic { 0 } else { 1 })
|
||||
.direction(Direction::Horizontal)
|
||||
.split(draw_loc)[0];
|
||||
|
||||
@ -135,7 +133,6 @@ impl<'a> TextTable<'a> {
|
||||
|
||||
if inner_width == 0 || inner_height == 0 {
|
||||
f.render_widget(disk_block, margined_draw_loc);
|
||||
margined_draw_loc
|
||||
} else {
|
||||
let show_header = inner_height > 1;
|
||||
let header_height = if show_header { 1 } else { 0 };
|
||||
@ -183,15 +180,24 @@ impl<'a> TextTable<'a> {
|
||||
|
||||
let columns = &state.columns;
|
||||
let widths = &state.calculated_widths;
|
||||
// TODO: Maybe truncate this too?
|
||||
let header = Row::new(columns.iter().map(|c| Text::raw(c.name.as_ref())))
|
||||
.style(self.header_style)
|
||||
.bottom_margin(table_gap);
|
||||
let header = Row::new(
|
||||
columns
|
||||
.iter()
|
||||
.zip(widths)
|
||||
.map(|(c, width)| truncate_text(&c.name, (*width).into(), None)),
|
||||
)
|
||||
.style(self.header_style)
|
||||
.bottom_margin(table_gap);
|
||||
let disk_rows = sliced_vec.iter().map(|row| {
|
||||
let (row, style) = match row {
|
||||
TableRow::Raw(row) => (row, None),
|
||||
TableRow::Styled(row, style) => (row, Some(*style)),
|
||||
};
|
||||
|
||||
Row::new(
|
||||
row.iter()
|
||||
.zip(widths)
|
||||
.map(|(cell, width)| truncate_text(cell, (*width).into())),
|
||||
.map(|(cell, width)| truncate_text(cell, (*width).into(), style)),
|
||||
)
|
||||
});
|
||||
|
||||
@ -218,21 +224,22 @@ impl<'a> TextTable<'a> {
|
||||
margined_draw_loc,
|
||||
&mut state.table_state,
|
||||
);
|
||||
|
||||
margined_draw_loc
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Truncates text if it is too long, and adds an ellipsis at the end if needed.
|
||||
fn truncate_text(content: &CellContent, width: usize) -> Text<'_> {
|
||||
fn truncate_text(content: &CellContent, width: usize, row_style: Option<Style>) -> Text<'_> {
|
||||
let (text, opt) = match content {
|
||||
CellContent::Simple(s) => (s, None),
|
||||
CellContent::HasShort { short, long } => (long, Some(short)),
|
||||
CellContent::HasAlt {
|
||||
alt: short,
|
||||
main: long,
|
||||
} => (long, Some(short)),
|
||||
};
|
||||
|
||||
let graphemes = UnicodeSegmentation::graphemes(text.as_ref(), true).collect::<Vec<&str>>();
|
||||
if graphemes.len() > width && width > 0 {
|
||||
let mut text = if graphemes.len() > width && width > 0 {
|
||||
if let Some(s) = opt {
|
||||
// If an alternative exists, use that.
|
||||
Text::raw(s.as_ref())
|
||||
@ -243,7 +250,13 @@ fn truncate_text(content: &CellContent, width: usize) -> Text<'_> {
|
||||
}
|
||||
} else {
|
||||
Text::raw(text.as_ref())
|
||||
};
|
||||
|
||||
if let Some(row_style) = row_style {
|
||||
text.patch_style(row_style);
|
||||
}
|
||||
|
||||
text
|
||||
}
|
||||
|
||||
/// Gets the starting position of a table.
|
||||
|
@ -183,7 +183,7 @@ impl Painter {
|
||||
);
|
||||
|
||||
let points = self.generate_points(
|
||||
&cpu_widget_state,
|
||||
cpu_widget_state,
|
||||
cpu_data,
|
||||
app_state.app_config_fields.show_average_cpu,
|
||||
);
|
||||
@ -224,7 +224,7 @@ impl Painter {
|
||||
let recalculate_column_widths = app_state.should_get_widget_bounds();
|
||||
if let Some(cpu_widget_state) = app_state.cpu_state.widget_states.get_mut(&(widget_id - 1))
|
||||
{
|
||||
cpu_widget_state.is_legend_hidden = false;
|
||||
cpu_widget_state.is_legend_hidden = false; // TODO: This line (and the one above, see caller) is pretty dumb.
|
||||
let cpu_data: &mut [ConvertedCpuData] = &mut app_state.canvas_data.cpu_data;
|
||||
let cpu_table_state = &mut cpu_widget_state.scroll_state.table_state;
|
||||
let is_on_widget = widget_id == app_state.current_widget.widget_id;
|
||||
|
@ -22,7 +22,7 @@ impl Painter {
|
||||
} else {
|
||||
(self.colours.border_style, self.colours.text_style)
|
||||
};
|
||||
let margined_draw_loc = TextTable {
|
||||
TextTable {
|
||||
table_gap: app_state.app_config_fields.table_gap,
|
||||
is_force_redraw: app_state.is_force_redraw,
|
||||
recalculate_column_widths,
|
||||
@ -48,11 +48,9 @@ impl Painter {
|
||||
if app_state.should_get_widget_bounds() {
|
||||
// Update draw loc in widget map
|
||||
if let Some(widget) = app_state.widget_map.get_mut(&widget_id) {
|
||||
widget.top_left_corner = Some((margined_draw_loc.x, margined_draw_loc.y));
|
||||
widget.bottom_right_corner = Some((
|
||||
margined_draw_loc.x + margined_draw_loc.width,
|
||||
margined_draw_loc.y + margined_draw_loc.height,
|
||||
));
|
||||
widget.top_left_corner = Some((draw_loc.x, draw_loc.y));
|
||||
widget.bottom_right_corner =
|
||||
Some((draw_loc.x + draw_loc.width, draw_loc.y + draw_loc.height));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ impl Painter {
|
||||
} else {
|
||||
(self.colours.border_style, self.colours.text_style)
|
||||
};
|
||||
let margined_draw_loc = TextTable {
|
||||
TextTable {
|
||||
table_gap: app_state.app_config_fields.table_gap,
|
||||
is_force_redraw: app_state.is_force_redraw,
|
||||
recalculate_column_widths,
|
||||
@ -47,13 +47,10 @@ impl Painter {
|
||||
|
||||
if app_state.should_get_widget_bounds() {
|
||||
// Update draw loc in widget map
|
||||
// Note there is no difference between this and using draw_loc, but I'm too lazy to fix it.
|
||||
if let Some(widget) = app_state.widget_map.get_mut(&widget_id) {
|
||||
widget.top_left_corner = Some((margined_draw_loc.x, margined_draw_loc.y));
|
||||
widget.bottom_right_corner = Some((
|
||||
margined_draw_loc.x + margined_draw_loc.width,
|
||||
margined_draw_loc.y + margined_draw_loc.height,
|
||||
));
|
||||
widget.top_left_corner = Some((draw_loc.x, draw_loc.y));
|
||||
widget.bottom_right_corner =
|
||||
Some((draw_loc.x + draw_loc.width, draw_loc.y + draw_loc.height));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,27 +25,38 @@ pub struct ConvertedBatteryData {
|
||||
|
||||
pub enum CellContent {
|
||||
Simple(Cow<'static, str>),
|
||||
HasShort {
|
||||
short: Cow<'static, str>,
|
||||
long: Cow<'static, str>,
|
||||
HasAlt {
|
||||
alt: Cow<'static, str>,
|
||||
main: Cow<'static, str>,
|
||||
},
|
||||
}
|
||||
|
||||
impl CellContent {
|
||||
/// Returns the length of the [`CellContent`]. Note that for a [`CellContent::HasAlt`], it will return
|
||||
/// the length of the "main" field.
|
||||
pub fn len(&self) -> usize {
|
||||
match self {
|
||||
CellContent::Simple(s) => s.len(),
|
||||
CellContent::HasShort { short: _, long } => long.len(),
|
||||
CellContent::HasAlt { alt: _, main: long } => long.len(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct TableData {
|
||||
pub data: Vec<Vec<CellContent>>,
|
||||
pub data: Vec<TableRow>,
|
||||
pub row_widths: Vec<usize>,
|
||||
}
|
||||
|
||||
pub enum TableRow {
|
||||
Raw(Vec<CellContent>),
|
||||
Styled(Vec<CellContent>, tui::style::Style),
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct ConvertedNetworkData {
|
||||
pub rx: Vec<Point>,
|
||||
@ -111,7 +122,7 @@ pub fn convert_temp_row(app: &App) -> TableData {
|
||||
let temp_type = &app.app_config_fields.temperature_type;
|
||||
let mut row_widths = vec![0; 2];
|
||||
|
||||
let mut sensor_vector: Vec<Vec<CellContent>> = current_data
|
||||
let mut sensor_vector: Vec<TableRow> = current_data
|
||||
.temp_harvest
|
||||
.iter()
|
||||
.map(|temp_harvest| {
|
||||
@ -134,15 +145,15 @@ pub fn convert_temp_row(app: &App) -> TableData {
|
||||
*curr = std::cmp::max(*curr, r.len());
|
||||
});
|
||||
|
||||
row
|
||||
TableRow::Raw(row)
|
||||
})
|
||||
.collect();
|
||||
|
||||
if sensor_vector.is_empty() {
|
||||
sensor_vector.push(vec![
|
||||
sensor_vector.push(TableRow::Raw(vec![
|
||||
CellContent::Simple("No Sensors Found".into()),
|
||||
CellContent::Simple("".into()),
|
||||
]);
|
||||
]));
|
||||
}
|
||||
|
||||
TableData {
|
||||
@ -152,7 +163,7 @@ pub fn convert_temp_row(app: &App) -> TableData {
|
||||
}
|
||||
|
||||
pub fn convert_disk_row(current_data: &data_farmer::DataCollection) -> TableData {
|
||||
let mut disk_vector: Vec<Vec<CellContent>> = Vec::new();
|
||||
let mut disk_vector: Vec<TableRow> = Vec::new();
|
||||
let mut row_widths = vec![0; 8];
|
||||
|
||||
current_data
|
||||
@ -197,14 +208,14 @@ pub fn convert_disk_row(current_data: &data_farmer::DataCollection) -> TableData
|
||||
row_widths.iter_mut().zip(&row).for_each(|(curr, r)| {
|
||||
*curr = std::cmp::max(*curr, r.len());
|
||||
});
|
||||
disk_vector.push(row);
|
||||
disk_vector.push(TableRow::Raw(row));
|
||||
});
|
||||
|
||||
if disk_vector.is_empty() {
|
||||
disk_vector.push(vec![
|
||||
disk_vector.push(TableRow::Raw(vec![
|
||||
CellContent::Simple("No Disks Found".into()),
|
||||
CellContent::Simple("".into()),
|
||||
]);
|
||||
]));
|
||||
}
|
||||
|
||||
TableData {
|
||||
|
Loading…
x
Reference in New Issue
Block a user