mirror of
https://github.com/ClementTsang/bottom.git
synced 2025-04-08 17:05:59 +02:00
refactor: move CPU graph over to new system
This commit is contained in:
parent
9e63642e9c
commit
c97126df22
12
src/app.rs
12
src/app.rs
@ -2228,8 +2228,8 @@ impl App {
|
||||
.cpu_state
|
||||
.get_mut_widget_state(self.current_widget.widget_id - 1)
|
||||
{
|
||||
cpu_widget_state.scroll_state.current_scroll_position = 0;
|
||||
cpu_widget_state.scroll_state.scroll_direction = ScrollDirection::Up;
|
||||
cpu_widget_state.table_state.current_scroll_position = 0;
|
||||
cpu_widget_state.table_state.scroll_direction = ScrollDirection::Up;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2306,8 +2306,8 @@ impl App {
|
||||
{
|
||||
let cap = self.canvas_data.cpu_data.len();
|
||||
if cap > 0 {
|
||||
cpu_widget_state.scroll_state.current_scroll_position = cap - 1;
|
||||
cpu_widget_state.scroll_state.scroll_direction = ScrollDirection::Down;
|
||||
cpu_widget_state.table_state.current_scroll_position = cap - 1;
|
||||
cpu_widget_state.table_state.scroll_direction = ScrollDirection::Down;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2380,7 +2380,7 @@ impl App {
|
||||
.get_mut(&(self.current_widget.widget_id - 1))
|
||||
{
|
||||
cpu_widget_state
|
||||
.scroll_state
|
||||
.table_state
|
||||
.update_position(num_to_change_by, self.canvas_data.cpu_data.len());
|
||||
}
|
||||
}
|
||||
@ -2957,7 +2957,7 @@ impl App {
|
||||
.get_widget_state(self.current_widget.widget_id - 1)
|
||||
{
|
||||
if let Some(visual_index) =
|
||||
cpu_widget_state.scroll_state.table_state.selected()
|
||||
cpu_widget_state.table_state.table_state.selected()
|
||||
{
|
||||
self.change_cpu_legend_position(
|
||||
offset_clicked_entry as i64 - visual_index as i64,
|
||||
|
@ -61,8 +61,19 @@ pub enum WidthBounds {
|
||||
|
||||
impl WidthBounds {
|
||||
pub const fn soft_from_str(name: &'static str, max_percentage: Option<f32>) -> WidthBounds {
|
||||
let len = name.len() as u16;
|
||||
WidthBounds::Soft {
|
||||
min_width: name.len() as u16,
|
||||
min_width: len,
|
||||
desired: len,
|
||||
max_percentage,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn soft_from_str_with_alt(
|
||||
name: &'static str, alt: &'static str, max_percentage: Option<f32>,
|
||||
) -> WidthBounds {
|
||||
WidthBounds::Soft {
|
||||
min_width: alt.len() as u16,
|
||||
desired: name.len() as u16,
|
||||
max_percentage,
|
||||
}
|
||||
@ -75,6 +86,9 @@ pub struct TableComponentColumn {
|
||||
|
||||
/// A restriction on this column's width, if desired.
|
||||
pub width_bounds: WidthBounds,
|
||||
|
||||
/// The calculated width of the column.
|
||||
pub calculated_width: u16,
|
||||
}
|
||||
|
||||
impl TableComponentColumn {
|
||||
@ -92,8 +106,13 @@ impl TableComponentColumn {
|
||||
CellContent::Simple(name.into())
|
||||
},
|
||||
width_bounds,
|
||||
calculated_width: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn should_skip(&self) -> bool {
|
||||
self.calculated_width == 0
|
||||
}
|
||||
}
|
||||
|
||||
/// [`TableComponentState`] deals with fields for a scrollable's current state.
|
||||
@ -104,7 +123,6 @@ pub struct TableComponentState {
|
||||
pub scroll_direction: ScrollDirection,
|
||||
pub table_state: TableState,
|
||||
pub columns: Vec<TableComponentColumn>,
|
||||
pub calculated_widths: Vec<u16>,
|
||||
}
|
||||
|
||||
impl TableComponentState {
|
||||
@ -115,7 +133,6 @@ impl TableComponentState {
|
||||
scroll_direction: ScrollDirection::Down,
|
||||
table_state: Default::default(),
|
||||
columns,
|
||||
calculated_widths: Vec::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,16 +149,18 @@ impl TableComponentState {
|
||||
|
||||
let mut total_width_left = total_width;
|
||||
|
||||
let column_widths = &mut self.calculated_widths;
|
||||
*column_widths = vec![0; self.columns.len()];
|
||||
for column in self.columns.iter_mut() {
|
||||
column.calculated_width = 0;
|
||||
}
|
||||
|
||||
let columns = if left_to_right {
|
||||
Either::Left(self.columns.iter().enumerate())
|
||||
Either::Left(self.columns.iter_mut())
|
||||
} else {
|
||||
Either::Right(self.columns.iter().enumerate().rev())
|
||||
Either::Right(self.columns.iter_mut().rev())
|
||||
};
|
||||
|
||||
for (itx, column) in columns {
|
||||
let mut num_columns = 0;
|
||||
for column in columns {
|
||||
match &column.width_bounds {
|
||||
WidthBounds::Soft {
|
||||
min_width,
|
||||
@ -161,9 +180,10 @@ impl TableComponentState {
|
||||
|
||||
if *min_width > space_taken {
|
||||
break;
|
||||
} else {
|
||||
} else if space_taken > 0 {
|
||||
total_width_left = total_width_left.saturating_sub(space_taken + 1);
|
||||
column_widths[itx] = space_taken;
|
||||
column.calculated_width = space_taken;
|
||||
num_columns += 1;
|
||||
}
|
||||
}
|
||||
WidthBounds::Hard(width) => {
|
||||
@ -171,27 +191,34 @@ impl TableComponentState {
|
||||
|
||||
if *width > space_taken {
|
||||
break;
|
||||
} else {
|
||||
} else if space_taken > 0 {
|
||||
total_width_left = total_width_left.saturating_sub(space_taken + 1);
|
||||
column_widths[itx] = space_taken;
|
||||
column.calculated_width = space_taken;
|
||||
num_columns += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while let Some(0) = column_widths.last() {
|
||||
column_widths.pop();
|
||||
}
|
||||
|
||||
if !column_widths.is_empty() {
|
||||
if num_columns > 0 {
|
||||
// Redistribute remaining.
|
||||
let amount_per_slot = total_width_left / column_widths.len() as u16;
|
||||
total_width_left %= column_widths.len() as u16;
|
||||
for (index, width) in column_widths.iter_mut().enumerate() {
|
||||
if index < total_width_left.into() {
|
||||
*width += amount_per_slot + 1;
|
||||
} else {
|
||||
*width += amount_per_slot;
|
||||
let mut num_dist = num_columns;
|
||||
let amount_per_slot = total_width_left / num_dist;
|
||||
total_width_left %= num_dist;
|
||||
for column in self.columns.iter_mut() {
|
||||
if num_dist == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
if column.calculated_width > 0 {
|
||||
if total_width_left > 0 {
|
||||
column.calculated_width += amount_per_slot + 1;
|
||||
total_width_left -= 1;
|
||||
} else {
|
||||
column.calculated_width += amount_per_slot;
|
||||
}
|
||||
|
||||
num_dist -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -871,29 +898,13 @@ impl ProcState {
|
||||
pub struct NetWidgetState {
|
||||
pub current_display_time: u64,
|
||||
pub autohide_timer: Option<Instant>,
|
||||
// pub draw_max_range_cache: f64,
|
||||
// pub draw_labels_cache: Vec<String>,
|
||||
// pub draw_time_start_cache: f64,
|
||||
// TODO: Re-enable these when we move net details state-side!
|
||||
// pub unit_type: DataUnitTypes,
|
||||
// pub scale_type: AxisScaling,
|
||||
}
|
||||
|
||||
impl NetWidgetState {
|
||||
pub fn init(
|
||||
current_display_time: u64,
|
||||
autohide_timer: Option<Instant>,
|
||||
// unit_type: DataUnitTypes,
|
||||
// scale_type: AxisScaling,
|
||||
) -> Self {
|
||||
pub fn init(current_display_time: u64, autohide_timer: Option<Instant>) -> Self {
|
||||
NetWidgetState {
|
||||
current_display_time,
|
||||
autohide_timer,
|
||||
// draw_max_range_cache: 0.0,
|
||||
// draw_labels_cache: vec![],
|
||||
// draw_time_start_cache: 0.0,
|
||||
// unit_type,
|
||||
// scale_type,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -924,20 +935,33 @@ pub struct CpuWidgetState {
|
||||
pub current_display_time: u64,
|
||||
pub is_legend_hidden: bool,
|
||||
pub autohide_timer: Option<Instant>,
|
||||
pub scroll_state: TableComponentState,
|
||||
pub table_state: TableComponentState,
|
||||
pub is_multi_graph_mode: bool,
|
||||
pub table_width_state: CanvasTableWidthState,
|
||||
}
|
||||
|
||||
impl CpuWidgetState {
|
||||
pub fn init(current_display_time: u64, autohide_timer: Option<Instant>) -> Self {
|
||||
const CPU_LEGEND_HEADER: [(Cow<'static, str>, Option<Cow<'static, str>>); 2] =
|
||||
[(Cow::Borrowed("CPU"), None), (Cow::Borrowed("Use%"), None)];
|
||||
const WIDTHS: [WidthBounds; CPU_LEGEND_HEADER.len()] = [
|
||||
WidthBounds::soft_from_str("CPU", Some(0.5)),
|
||||
WidthBounds::soft_from_str("Use%", Some(0.5)),
|
||||
];
|
||||
|
||||
let table_state = TableComponentState::new(
|
||||
CPU_LEGEND_HEADER
|
||||
.iter()
|
||||
.zip(WIDTHS)
|
||||
.map(|(c, width)| TableComponentColumn::new(c.0.clone(), c.1.clone(), width))
|
||||
.collect(),
|
||||
);
|
||||
|
||||
CpuWidgetState {
|
||||
current_display_time,
|
||||
is_legend_hidden: false,
|
||||
autohide_timer,
|
||||
scroll_state: TableComponentState::default(),
|
||||
table_state,
|
||||
is_multi_graph_mode: false,
|
||||
table_width_state: CanvasTableWidthState::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1166,7 +1190,6 @@ mod test {
|
||||
scroll_direction: ScrollDirection::Down,
|
||||
table_state: Default::default(),
|
||||
columns: vec![],
|
||||
calculated_widths: vec![],
|
||||
};
|
||||
let s = &mut scroll;
|
||||
|
||||
|
@ -17,6 +17,11 @@ use crate::{
|
||||
data_conversion::{CellContent, TableData, TableRow},
|
||||
};
|
||||
|
||||
pub struct TextTableTitle<'a> {
|
||||
pub title: Cow<'a, str>,
|
||||
pub is_expanded: bool,
|
||||
}
|
||||
|
||||
pub struct TextTable<'a> {
|
||||
pub table_gap: u16,
|
||||
pub is_force_redraw: bool,
|
||||
@ -31,11 +36,8 @@ pub struct TextTable<'a> {
|
||||
/// The highlighted text style.
|
||||
pub highlighted_text_style: Style,
|
||||
|
||||
/// The graph title.
|
||||
pub title: Cow<'a, str>,
|
||||
|
||||
/// Whether this graph is expanded.
|
||||
pub is_expanded: bool,
|
||||
/// The graph title and whether it is expanded (if there is one).
|
||||
pub title: Option<TextTableTitle<'a>>,
|
||||
|
||||
/// Whether this widget is selected.
|
||||
pub is_on_widget: bool,
|
||||
@ -58,42 +60,46 @@ pub struct TextTable<'a> {
|
||||
|
||||
impl<'a> TextTable<'a> {
|
||||
/// Generates a title for the [`TextTable`] widget, given the available space.
|
||||
fn generate_title(&self, draw_loc: Rect, pos: usize, total: usize) -> Spans<'_> {
|
||||
let title = if self.show_table_scroll_position {
|
||||
let title_string = concat_string!(
|
||||
self.title,
|
||||
"(",
|
||||
pos.to_string(),
|
||||
" of ",
|
||||
total.to_string(),
|
||||
") "
|
||||
);
|
||||
fn generate_title(&self, draw_loc: Rect, pos: usize, total: usize) -> Option<Spans<'_>> {
|
||||
self.title
|
||||
.as_ref()
|
||||
.map(|TextTableTitle { title, is_expanded }| {
|
||||
let title = if self.show_table_scroll_position {
|
||||
let title_string = concat_string!(
|
||||
title,
|
||||
"(",
|
||||
pos.to_string(),
|
||||
" of ",
|
||||
total.to_string(),
|
||||
") "
|
||||
);
|
||||
|
||||
if title_string.len() + 2 <= draw_loc.width.into() {
|
||||
title_string
|
||||
} else {
|
||||
self.title.to_string()
|
||||
}
|
||||
} else {
|
||||
self.title.to_string()
|
||||
};
|
||||
if title_string.len() + 2 <= draw_loc.width.into() {
|
||||
title_string
|
||||
} else {
|
||||
title.to_string()
|
||||
}
|
||||
} else {
|
||||
title.to_string()
|
||||
};
|
||||
|
||||
if self.is_expanded {
|
||||
let title_base = concat_string!(title, "── Esc to go back ");
|
||||
let esc = concat_string!(
|
||||
"─",
|
||||
"─".repeat(usize::from(draw_loc.width).saturating_sub(
|
||||
UnicodeSegmentation::graphemes(title_base.as_str(), true).count() + 2
|
||||
)),
|
||||
"─ Esc to go back "
|
||||
);
|
||||
Spans::from(vec![
|
||||
Span::styled(title, self.title_style),
|
||||
Span::styled(esc, self.border_style),
|
||||
])
|
||||
} else {
|
||||
Spans::from(Span::styled(title, self.title_style))
|
||||
}
|
||||
if *is_expanded {
|
||||
let title_base = concat_string!(title, "── Esc to go back ");
|
||||
let esc = concat_string!(
|
||||
"─",
|
||||
"─".repeat(usize::from(draw_loc.width).saturating_sub(
|
||||
UnicodeSegmentation::graphemes(title_base.as_str(), true).count() + 2
|
||||
)),
|
||||
"─ Esc to go back "
|
||||
);
|
||||
Spans::from(vec![
|
||||
Span::styled(title, self.title_style),
|
||||
Span::styled(esc, self.border_style),
|
||||
])
|
||||
} else {
|
||||
Spans::from(Span::styled(title, self.title_style))
|
||||
}
|
||||
})
|
||||
}
|
||||
pub fn draw_text_table<B: Backend>(
|
||||
&self, f: &mut Frame<'_, B>, draw_loc: Rect, state: &mut TableComponentState,
|
||||
@ -108,16 +114,19 @@ impl<'a> TextTable<'a> {
|
||||
.split(draw_loc)[0];
|
||||
|
||||
let disk_block = if self.draw_border {
|
||||
let title = self.generate_title(
|
||||
let block = Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.border_style(self.border_style);
|
||||
|
||||
if let Some(title) = self.generate_title(
|
||||
draw_loc,
|
||||
state.current_scroll_position.saturating_add(1),
|
||||
table_data.data.len(),
|
||||
);
|
||||
|
||||
Block::default()
|
||||
.title(title)
|
||||
.borders(Borders::ALL)
|
||||
.border_style(self.border_style)
|
||||
) {
|
||||
block.title(title)
|
||||
} else {
|
||||
block
|
||||
}
|
||||
} else if self.is_on_widget {
|
||||
Block::default()
|
||||
.borders(SIDE_BORDERS)
|
||||
@ -179,30 +188,32 @@ impl<'a> TextTable<'a> {
|
||||
}
|
||||
|
||||
let columns = &state.columns;
|
||||
let widths = &state.calculated_widths;
|
||||
let header = Row::new(
|
||||
columns
|
||||
.iter()
|
||||
.zip(widths)
|
||||
.map(|(c, width)| truncate_text(&c.name, (*width).into(), None)),
|
||||
)
|
||||
let header = Row::new(columns.iter().filter_map(|c| {
|
||||
if c.calculated_width == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(truncate_text(&c.name, c.calculated_width.into(), None))
|
||||
}
|
||||
}))
|
||||
.style(self.header_style)
|
||||
.bottom_margin(table_gap);
|
||||
let disk_rows = sliced_vec.iter().map(|row| {
|
||||
let table_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(), style)),
|
||||
)
|
||||
Row::new(row.iter().zip(columns).filter_map(|(cell, c)| {
|
||||
if c.calculated_width == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(truncate_text(cell, c.calculated_width.into(), style))
|
||||
}
|
||||
}))
|
||||
});
|
||||
|
||||
let widget = {
|
||||
let mut table = Table::new(disk_rows)
|
||||
let mut table = Table::new(table_rows)
|
||||
.block(disk_block)
|
||||
.highlight_style(self.highlighted_text_style)
|
||||
.style(self.text_style);
|
||||
@ -216,9 +227,15 @@ impl<'a> TextTable<'a> {
|
||||
|
||||
f.render_stateful_widget(
|
||||
widget.widths(
|
||||
&(widths
|
||||
&(columns
|
||||
.iter()
|
||||
.map(|w| Constraint::Length(*w))
|
||||
.filter_map(|c| {
|
||||
if c.calculated_width == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(Constraint::Length(c.calculated_width))
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()),
|
||||
),
|
||||
margined_draw_loc,
|
||||
|
@ -1,38 +1,34 @@
|
||||
use std::borrow::Cow;
|
||||
use std::{borrow::Cow, iter};
|
||||
|
||||
use crate::{
|
||||
app::{layout_manager::WidgetDirection, App, CpuWidgetState},
|
||||
canvas::{
|
||||
components::{GraphData, TimeGraph},
|
||||
drawing_utils::{get_column_widths, get_start_position, should_hide_x_label},
|
||||
components::{GraphData, TextTable, TimeGraph},
|
||||
drawing_utils::should_hide_x_label,
|
||||
Painter,
|
||||
},
|
||||
constants::*,
|
||||
data_conversion::ConvertedCpuData,
|
||||
data_conversion::{CellContent, ConvertedCpuData, TableData, TableRow},
|
||||
};
|
||||
|
||||
use concat_string::concat_string;
|
||||
|
||||
use itertools::Either;
|
||||
use tui::{
|
||||
backend::Backend,
|
||||
layout::{Constraint, Direction, Layout, Rect},
|
||||
terminal::Frame,
|
||||
text::Text,
|
||||
widgets::{Block, Borders, Row, Table},
|
||||
};
|
||||
|
||||
const CPU_LEGEND_HEADER: [&str; 2] = ["CPU", "Use%"];
|
||||
const AVG_POSITION: usize = 1;
|
||||
const ALL_POSITION: usize = 0;
|
||||
|
||||
static CPU_LEGEND_HEADER_LENS: [usize; 2] =
|
||||
[CPU_LEGEND_HEADER[0].len(), CPU_LEGEND_HEADER[1].len()];
|
||||
|
||||
impl Painter {
|
||||
pub fn draw_cpu<B: Backend>(
|
||||
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64,
|
||||
) {
|
||||
if draw_loc.width as f64 * 0.15 <= 6.0 {
|
||||
let legend_width = (draw_loc.width as f64 * 0.15) as u16;
|
||||
|
||||
if legend_width < 6 {
|
||||
// Skip drawing legend
|
||||
if app_state.current_widget.widget_id == (widget_id + 1) {
|
||||
if app_state.app_config_fields.left_legend {
|
||||
@ -55,18 +51,25 @@ impl Painter {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let graph_width = draw_loc.width - legend_width;
|
||||
let (graph_index, legend_index, constraints) =
|
||||
if app_state.app_config_fields.left_legend {
|
||||
(
|
||||
1,
|
||||
0,
|
||||
[Constraint::Percentage(15), Constraint::Percentage(85)],
|
||||
[
|
||||
Constraint::Length(legend_width),
|
||||
Constraint::Length(graph_width),
|
||||
],
|
||||
)
|
||||
} else {
|
||||
(
|
||||
0,
|
||||
1,
|
||||
[Constraint::Percentage(85), Constraint::Percentage(15)],
|
||||
[
|
||||
Constraint::Length(graph_width),
|
||||
Constraint::Length(legend_width),
|
||||
],
|
||||
)
|
||||
};
|
||||
|
||||
@ -121,7 +124,7 @@ impl Painter {
|
||||
) -> Vec<GraphData<'a>> {
|
||||
let show_avg_offset = if show_avg_cpu { AVG_POSITION } else { 0 };
|
||||
|
||||
let current_scroll_position = cpu_widget_state.scroll_state.current_scroll_position;
|
||||
let current_scroll_position = cpu_widget_state.table_state.current_scroll_position;
|
||||
if current_scroll_position == ALL_POSITION {
|
||||
// This case ensures the other cases cannot have the position be equal to 0.
|
||||
cpu_data
|
||||
@ -224,149 +227,81 @@ 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; // 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;
|
||||
let table_gap = if draw_loc.height < TABLE_GAP_HEIGHT_LIMIT {
|
||||
0
|
||||
} else {
|
||||
app_state.app_config_fields.table_gap
|
||||
};
|
||||
let start_position = get_start_position(
|
||||
usize::from(
|
||||
(draw_loc.height + (1 - table_gap)).saturating_sub(self.table_height_offset),
|
||||
),
|
||||
&cpu_widget_state.scroll_state.scroll_direction,
|
||||
&mut cpu_widget_state.scroll_state.scroll_bar,
|
||||
cpu_widget_state.scroll_state.current_scroll_position,
|
||||
app_state.is_force_redraw,
|
||||
);
|
||||
cpu_table_state.select(Some(
|
||||
cpu_widget_state
|
||||
.scroll_state
|
||||
.current_scroll_position
|
||||
.saturating_sub(start_position),
|
||||
));
|
||||
// TODO: This line (and the one above, see caller) is pretty dumb but I guess needed.
|
||||
cpu_widget_state.is_legend_hidden = false;
|
||||
|
||||
let sliced_cpu_data = &cpu_data[start_position..];
|
||||
|
||||
let offset_scroll_index = cpu_widget_state
|
||||
.scroll_state
|
||||
.current_scroll_position
|
||||
.saturating_sub(start_position);
|
||||
let show_avg_cpu = app_state.app_config_fields.show_average_cpu;
|
||||
|
||||
// Calculate widths
|
||||
if recalculate_column_widths {
|
||||
cpu_widget_state.table_width_state.desired_column_widths = vec![6, 4];
|
||||
cpu_widget_state.table_width_state.calculated_column_widths = get_column_widths(
|
||||
draw_loc.width,
|
||||
&[None, None],
|
||||
&(CPU_LEGEND_HEADER_LENS
|
||||
.iter()
|
||||
.map(|width| Some(*width as u16))
|
||||
.collect::<Vec<_>>()),
|
||||
&[Some(0.5), Some(0.5)],
|
||||
&(cpu_widget_state
|
||||
.table_width_state
|
||||
.desired_column_widths
|
||||
.iter()
|
||||
.map(|width| Some(*width))
|
||||
.collect::<Vec<_>>()),
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
let dcw = &cpu_widget_state.table_width_state.desired_column_widths;
|
||||
let ccw = &cpu_widget_state.table_width_state.calculated_column_widths;
|
||||
let cpu_rows = sliced_cpu_data.iter().enumerate().map(|(itx, cpu)| {
|
||||
let mut truncated_name =
|
||||
if let (Some(desired_column_width), Some(calculated_column_width)) =
|
||||
(dcw.get(0), ccw.get(0))
|
||||
{
|
||||
if *desired_column_width > *calculated_column_width {
|
||||
Text::raw(&cpu.short_cpu_name)
|
||||
} else {
|
||||
Text::raw(&cpu.cpu_name)
|
||||
}
|
||||
} else {
|
||||
Text::raw(&cpu.cpu_name)
|
||||
};
|
||||
|
||||
let is_first_column_hidden = if let Some(calculated_column_width) = ccw.get(0) {
|
||||
*calculated_column_width == 0
|
||||
let cpu_data = {
|
||||
let row_widths = vec![1, 3]; // TODO: Should change this to take const generics (usize) and an array.
|
||||
let colour_iter = if show_avg_cpu {
|
||||
Either::Left(
|
||||
iter::once(&self.colours.all_colour_style)
|
||||
.chain(iter::once(&self.colours.avg_colour_style))
|
||||
.chain(self.colours.cpu_colour_styles.iter().cycle()),
|
||||
)
|
||||
} else {
|
||||
false
|
||||
Either::Right(
|
||||
iter::once(&self.colours.all_colour_style)
|
||||
.chain(self.colours.cpu_colour_styles.iter().cycle()),
|
||||
)
|
||||
};
|
||||
|
||||
let truncated_legend = if is_first_column_hidden && cpu.legend_value.is_empty() {
|
||||
// For the case where we only have room for one column, display "All" in the normally blank area.
|
||||
Text::raw("All")
|
||||
} else {
|
||||
Text::raw(&cpu.legend_value)
|
||||
};
|
||||
|
||||
if !is_first_column_hidden
|
||||
&& itx == offset_scroll_index
|
||||
&& itx + start_position == ALL_POSITION
|
||||
{
|
||||
truncated_name.patch_style(self.colours.currently_selected_text_style);
|
||||
Row::new(vec![truncated_name, truncated_legend])
|
||||
} else {
|
||||
let cpu_string_row = vec![truncated_name, truncated_legend];
|
||||
|
||||
Row::new(cpu_string_row).style(if itx == offset_scroll_index {
|
||||
self.colours.currently_selected_text_style
|
||||
} else if itx + start_position == ALL_POSITION {
|
||||
self.colours.all_colour_style
|
||||
} else if show_avg_cpu {
|
||||
if itx + start_position == AVG_POSITION {
|
||||
self.colours.avg_colour_style
|
||||
} else {
|
||||
self.colours.cpu_colour_styles[(itx + start_position
|
||||
- AVG_POSITION
|
||||
- 1)
|
||||
% self.colours.cpu_colour_styles.len()]
|
||||
}
|
||||
let data = {
|
||||
let iter = app_state.canvas_data.cpu_data.iter().zip(colour_iter);
|
||||
const CPU_WIDTH_CHECK: u16 = 10; // This is hard-coded, it's terrible.
|
||||
if draw_loc.width < CPU_WIDTH_CHECK {
|
||||
Either::Left(iter.map(|(cpu, style)| {
|
||||
let row = vec![
|
||||
CellContent::Simple("".into()),
|
||||
CellContent::Simple(if cpu.legend_value.is_empty() {
|
||||
cpu.cpu_name.clone().into()
|
||||
} else {
|
||||
cpu.legend_value.clone().into()
|
||||
}),
|
||||
];
|
||||
TableRow::Styled(row, *style)
|
||||
}))
|
||||
} else {
|
||||
self.colours.cpu_colour_styles[(itx + start_position - ALL_POSITION - 1)
|
||||
% self.colours.cpu_colour_styles.len()]
|
||||
})
|
||||
Either::Right(iter.map(|(cpu, style)| {
|
||||
let row = vec![
|
||||
CellContent::HasAlt {
|
||||
alt: cpu.short_cpu_name.clone().into(),
|
||||
main: cpu.cpu_name.clone().into(),
|
||||
},
|
||||
CellContent::Simple(cpu.legend_value.clone().into()),
|
||||
];
|
||||
TableRow::Styled(row, *style)
|
||||
}))
|
||||
}
|
||||
}
|
||||
});
|
||||
.collect();
|
||||
|
||||
// Note we don't set highlight_style, as it should always be shown for this widget.
|
||||
let border_and_title_style = if is_on_widget {
|
||||
TableData { data, row_widths }
|
||||
};
|
||||
|
||||
let is_on_widget = widget_id == app_state.current_widget.widget_id;
|
||||
let border_style = if is_on_widget {
|
||||
self.colours.highlighted_border_style
|
||||
} else {
|
||||
self.colours.border_style
|
||||
};
|
||||
|
||||
// Draw
|
||||
f.render_stateful_widget(
|
||||
Table::new(cpu_rows)
|
||||
.block(
|
||||
Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.border_style(border_and_title_style),
|
||||
)
|
||||
.header(
|
||||
Row::new(CPU_LEGEND_HEADER.to_vec())
|
||||
.style(self.colours.table_header_style)
|
||||
.bottom_margin(table_gap),
|
||||
)
|
||||
.widths(
|
||||
&(cpu_widget_state
|
||||
.table_width_state
|
||||
.calculated_column_widths
|
||||
.iter()
|
||||
.map(|calculated_width| Constraint::Length(*calculated_width as u16))
|
||||
.collect::<Vec<_>>()),
|
||||
),
|
||||
draw_loc,
|
||||
cpu_table_state,
|
||||
);
|
||||
TextTable {
|
||||
table_gap: app_state.app_config_fields.table_gap,
|
||||
is_force_redraw: app_state.is_force_redraw,
|
||||
recalculate_column_widths,
|
||||
header_style: self.colours.table_header_style,
|
||||
border_style,
|
||||
highlighted_text_style: self.colours.currently_selected_text_style, // We always highlight the selected CPU entry... not sure if I like this though.
|
||||
title: None,
|
||||
is_on_widget,
|
||||
draw_border: true,
|
||||
show_table_scroll_position: app_state.app_config_fields.show_table_scroll_position,
|
||||
title_style: self.colours.widget_title_style,
|
||||
text_style: self.colours.text_style,
|
||||
left_to_right: false,
|
||||
}
|
||||
.draw_text_table(f, draw_loc, &mut cpu_widget_state.table_state, &cpu_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,10 @@ use tui::{backend::Backend, layout::Rect, terminal::Frame};
|
||||
|
||||
use crate::{
|
||||
app,
|
||||
canvas::{components::TextTable, Painter},
|
||||
canvas::{
|
||||
components::{TextTable, TextTableTitle},
|
||||
Painter,
|
||||
},
|
||||
};
|
||||
|
||||
impl Painter {
|
||||
@ -13,7 +16,6 @@ impl Painter {
|
||||
let recalculate_column_widths = app_state.should_get_widget_bounds();
|
||||
if let Some(disk_widget_state) = app_state.disk_state.widget_states.get_mut(&widget_id) {
|
||||
let is_on_widget = app_state.current_widget.widget_id == widget_id;
|
||||
|
||||
let (border_style, highlighted_text_style) = if is_on_widget {
|
||||
(
|
||||
self.colours.highlighted_border_style,
|
||||
@ -29,8 +31,10 @@ impl Painter {
|
||||
header_style: self.colours.table_header_style,
|
||||
border_style,
|
||||
highlighted_text_style,
|
||||
title: " Disks ".into(),
|
||||
is_expanded: app_state.is_expanded,
|
||||
title: Some(TextTableTitle {
|
||||
title: " Disks ".into(),
|
||||
is_expanded: app_state.is_expanded,
|
||||
}),
|
||||
is_on_widget,
|
||||
draw_border,
|
||||
show_table_scroll_position: app_state.app_config_fields.show_table_scroll_position,
|
||||
|
@ -2,7 +2,10 @@ use tui::{backend::Backend, layout::Rect, terminal::Frame};
|
||||
|
||||
use crate::{
|
||||
app,
|
||||
canvas::{components::TextTable, Painter},
|
||||
canvas::{
|
||||
components::{TextTable, TextTableTitle},
|
||||
Painter,
|
||||
},
|
||||
};
|
||||
|
||||
impl Painter {
|
||||
@ -29,8 +32,10 @@ impl Painter {
|
||||
header_style: self.colours.table_header_style,
|
||||
border_style,
|
||||
highlighted_text_style,
|
||||
title: " Temperatures ".into(),
|
||||
is_expanded: app_state.is_expanded,
|
||||
title: Some(TextTableTitle {
|
||||
title: " Temperatures ".into(),
|
||||
is_expanded: app_state.is_expanded,
|
||||
}),
|
||||
is_on_widget,
|
||||
draw_border,
|
||||
show_table_scroll_position: app_state.app_config_fields.show_table_scroll_position,
|
||||
|
@ -238,7 +238,7 @@ pub fn convert_cpu_data_points(
|
||||
if data.cpu_data.len() + 1 != existing_cpu_data.len() {
|
||||
*existing_cpu_data = vec![ConvertedCpuData {
|
||||
cpu_name: "All".to_string(),
|
||||
short_cpu_name: "All".to_string(),
|
||||
short_cpu_name: "".to_string(),
|
||||
cpu_data: vec![],
|
||||
legend_value: String::new(),
|
||||
}];
|
||||
|
Loading…
x
Reference in New Issue
Block a user