refactor: per-row styling, remove seemingly redundant table code

This commit is contained in:
ClementTsang 2022-05-03 04:46:43 -04:00
parent 2e51590bf5
commit df1a418327
6 changed files with 75 additions and 52 deletions

View File

@ -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,
}
}

View File

@ -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.

View File

@ -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;

View File

@ -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));
}
}
}

View File

@ -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));
}
}
}

View File

@ -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 {