mirror of
https://github.com/ClementTsang/bottom
synced 2024-11-29 15:40:19 +00:00
Move to stateful except for CPU
This commit is contained in:
parent
83dad154b9
commit
0574678746
8 changed files with 100 additions and 137 deletions
|
@ -3,6 +3,8 @@ use std::{cmp::max, collections::HashMap, time::Instant};
|
|||
use unicode_segmentation::GraphemeCursor;
|
||||
use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
|
||||
|
||||
use tui::widgets::TableState;
|
||||
|
||||
use typed_builder::*;
|
||||
|
||||
use data_farmer::*;
|
||||
|
@ -47,6 +49,7 @@ pub struct AppScrollWidgetState {
|
|||
pub current_scroll_position: u64,
|
||||
pub previous_scroll_position: u64,
|
||||
pub scroll_direction: ScrollDirection,
|
||||
pub table_state: TableState,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -91,7 +94,7 @@ pub struct AppConfigFields {
|
|||
pub hide_time: bool,
|
||||
pub autohide_time: bool,
|
||||
pub use_old_network_legend: bool,
|
||||
pub table_gap: u16
|
||||
pub table_gap: u16,
|
||||
}
|
||||
|
||||
/// AppSearchState deals with generic searching (I might do this in the future).
|
||||
|
|
|
@ -69,10 +69,11 @@ pub struct Painter {
|
|||
layout_constraints: Vec<Vec<Vec<Vec<Constraint>>>>,
|
||||
widget_layout: BottomLayout,
|
||||
derived_widget_draw_locs: Vec<Vec<Vec<Vec<Rect>>>>,
|
||||
table_height_offset: i64,
|
||||
}
|
||||
|
||||
impl Painter {
|
||||
pub fn init(widget_layout: BottomLayout) -> Self {
|
||||
pub fn init(widget_layout: BottomLayout, table_gap: u16) -> Self {
|
||||
// Now for modularity; we have to also initialize the base layouts!
|
||||
// We want to do this ONCE and reuse; after this we can just construct
|
||||
// based on the console size.
|
||||
|
@ -154,6 +155,7 @@ impl Painter {
|
|||
layout_constraints,
|
||||
widget_layout,
|
||||
derived_widget_draw_locs: Vec::new(),
|
||||
table_height_offset: 4 + table_gap as i64,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -217,7 +217,7 @@ impl CpuGraphWidget for Painter {
|
|||
cpu_widget_state.is_legend_hidden = false;
|
||||
let cpu_data: &mut [ConvertedCpuData] = &mut app_state.canvas_data.cpu_data;
|
||||
|
||||
let num_rows = max(0, i64::from(draw_loc.height) - 5) as u64;
|
||||
let num_rows = max(0, i64::from(draw_loc.height) - self.table_height_offset) as u64;
|
||||
let start_position = get_start_position(
|
||||
num_rows,
|
||||
&cpu_widget_state.scroll_state.scroll_direction,
|
||||
|
@ -225,13 +225,13 @@ impl CpuGraphWidget for Painter {
|
|||
cpu_widget_state.scroll_state.current_scroll_position,
|
||||
app_state.is_resized,
|
||||
);
|
||||
let is_on_widget = widget_id == app_state.current_widget.widget_id;
|
||||
|
||||
let sliced_cpu_data = &cpu_data[start_position as usize..];
|
||||
|
||||
let mut offset_scroll_index =
|
||||
(cpu_widget_state.scroll_state.current_scroll_position - start_position) as usize;
|
||||
let show_disabled_data = app_state.app_config_fields.show_disabled_data;
|
||||
let current_widget_id = app_state.current_widget.widget_id;
|
||||
let show_avg_cpu = app_state.app_config_fields.show_average_cpu;
|
||||
|
||||
let cpu_rows = sliced_cpu_data.iter().enumerate().filter_map(|(itx, cpu)| {
|
||||
|
@ -267,7 +267,7 @@ impl CpuGraphWidget for Painter {
|
|||
} else {
|
||||
Some(Row::StyledData(
|
||||
cpu_string_row.into_iter(),
|
||||
if current_widget_id == widget_id {
|
||||
if is_on_widget {
|
||||
if itx == offset_scroll_index {
|
||||
self.colours.currently_selected_text_style
|
||||
} else if show_avg_cpu && itx == 0 {
|
||||
|
@ -315,10 +315,13 @@ impl CpuGraphWidget for Painter {
|
|||
"".to_string()
|
||||
};
|
||||
|
||||
let title_and_border_style = if app_state.current_widget.widget_id == widget_id {
|
||||
self.colours.highlighted_border_style
|
||||
let (border_and_title_style, highlight_style) = if is_on_widget {
|
||||
(
|
||||
self.colours.highlighted_border_style,
|
||||
self.colours.currently_selected_text_style,
|
||||
)
|
||||
} else {
|
||||
self.colours.border_style
|
||||
(self.colours.border_style, self.colours.text_style)
|
||||
};
|
||||
|
||||
// Draw
|
||||
|
@ -335,11 +338,12 @@ impl CpuGraphWidget for Painter {
|
|||
.block(
|
||||
Block::default()
|
||||
.title(&title)
|
||||
.title_style(title_and_border_style)
|
||||
.title_style(border_and_title_style)
|
||||
.borders(Borders::ALL)
|
||||
.border_style(title_and_border_style),
|
||||
.border_style(border_and_title_style),
|
||||
)
|
||||
.header_style(self.colours.table_header_style)
|
||||
.highlight_style(highlight_style)
|
||||
.widths(
|
||||
&(intrinsic_widths
|
||||
.iter()
|
||||
|
|
|
@ -39,7 +39,7 @@ impl DiskTableWidget for Painter {
|
|||
) {
|
||||
if let Some(disk_widget_state) = app_state.disk_state.widget_states.get_mut(&widget_id) {
|
||||
let disk_data: &mut [Vec<String>] = &mut app_state.canvas_data.disk_data;
|
||||
let num_rows = max(0, i64::from(draw_loc.height) - 5) as u64;
|
||||
let num_rows = max(0, i64::from(draw_loc.height) - self.table_height_offset) as u64;
|
||||
let start_position = get_start_position(
|
||||
num_rows,
|
||||
&disk_widget_state.scroll_state.scroll_direction,
|
||||
|
@ -47,34 +47,14 @@ impl DiskTableWidget for Painter {
|
|||
disk_widget_state.scroll_state.current_scroll_position,
|
||||
app_state.is_resized,
|
||||
);
|
||||
let is_on_widget = app_state.current_widget.widget_id == widget_id;
|
||||
let disk_table_state = &mut disk_widget_state.scroll_state.table_state;
|
||||
disk_table_state.select(Some(
|
||||
(disk_widget_state.scroll_state.current_scroll_position - start_position) as usize,
|
||||
));
|
||||
|
||||
let sliced_vec = &mut disk_data[start_position as usize..];
|
||||
let mut disk_counter: i64 = 0;
|
||||
|
||||
let current_widget_id = app_state.current_widget.widget_id;
|
||||
let disk_rows = sliced_vec.iter().map(|disk| {
|
||||
Row::StyledData(
|
||||
disk.iter(),
|
||||
if current_widget_id == widget_id
|
||||
&& disk_widget_state.scroll_state.current_scroll_position >= start_position
|
||||
{
|
||||
if disk_counter as u64
|
||||
== disk_widget_state.scroll_state.current_scroll_position
|
||||
- start_position
|
||||
{
|
||||
disk_counter = -1;
|
||||
self.colours.currently_selected_text_style
|
||||
} else {
|
||||
if disk_counter >= 0 {
|
||||
disk_counter += 1;
|
||||
}
|
||||
self.colours.text_style
|
||||
}
|
||||
} else {
|
||||
self.colours.text_style
|
||||
},
|
||||
)
|
||||
});
|
||||
let disk_rows = sliced_vec.iter().map(|disk| Row::Data(disk.iter()));
|
||||
|
||||
// Calculate widths
|
||||
// TODO: [PRETTY] Ellipsis on strings?
|
||||
|
@ -101,10 +81,13 @@ impl DiskTableWidget for Painter {
|
|||
" Disk ".to_string()
|
||||
};
|
||||
|
||||
let border_and_title_style = if app_state.current_widget.widget_id == widget_id {
|
||||
self.colours.highlighted_border_style
|
||||
let (border_and_title_style, highlight_style) = if is_on_widget {
|
||||
(
|
||||
self.colours.highlighted_border_style,
|
||||
self.colours.currently_selected_text_style,
|
||||
)
|
||||
} else {
|
||||
self.colours.border_style
|
||||
(self.colours.border_style, self.colours.text_style)
|
||||
};
|
||||
|
||||
let disk_block = if draw_border {
|
||||
|
@ -117,7 +100,7 @@ impl DiskTableWidget for Painter {
|
|||
})
|
||||
.borders(Borders::ALL)
|
||||
.border_style(border_and_title_style)
|
||||
} else if app_state.current_widget.widget_id == widget_id {
|
||||
} else if is_on_widget {
|
||||
Block::default()
|
||||
.borders(*SIDE_BORDERS)
|
||||
.border_style(self.colours.highlighted_border_style)
|
||||
|
@ -127,21 +110,17 @@ impl DiskTableWidget for Painter {
|
|||
|
||||
let margined_draw_loc = Layout::default()
|
||||
.constraints([Constraint::Percentage(100)].as_ref())
|
||||
.horizontal_margin(
|
||||
if app_state.current_widget.widget_id == widget_id || draw_border {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
},
|
||||
)
|
||||
.horizontal_margin(if is_on_widget || draw_border { 0 } else { 1 })
|
||||
.direction(Direction::Horizontal)
|
||||
.split(draw_loc);
|
||||
|
||||
// Draw!
|
||||
f.render_widget(
|
||||
f.render_stateful_widget(
|
||||
Table::new(DISK_HEADERS.iter(), disk_rows)
|
||||
.block(disk_block)
|
||||
.header_style(self.colours.table_header_style)
|
||||
.highlight_style(highlight_style)
|
||||
.style(self.colours.text_style)
|
||||
.widths(
|
||||
&(intrinsic_widths
|
||||
.iter()
|
||||
|
@ -150,6 +129,7 @@ impl DiskTableWidget for Painter {
|
|||
)
|
||||
.header_gap(app_state.app_config_fields.table_gap),
|
||||
margined_draw_loc[0],
|
||||
disk_table_state,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ impl ProcessTableWidget for Painter {
|
|||
// hit the process we've currently scrolled to.
|
||||
// We also need to move the list - we can
|
||||
// do so by hiding some elements!
|
||||
let num_rows = max(0, i64::from(draw_loc.height) - 5) as u64;
|
||||
let num_rows = max(0, i64::from(draw_loc.height) - self.table_height_offset) as u64;
|
||||
let is_on_widget = widget_id == app_state.current_widget.widget_id;
|
||||
|
||||
let position = get_start_position(
|
||||
|
@ -102,43 +102,32 @@ impl ProcessTableWidget for Painter {
|
|||
};
|
||||
|
||||
let sliced_vec = &process_data[start_position as usize..];
|
||||
let mut process_counter: i64 = 0;
|
||||
let proc_table_state = &mut proc_widget_state.scroll_state.table_state;
|
||||
proc_table_state.select(Some(
|
||||
(proc_widget_state.scroll_state.current_scroll_position - start_position)
|
||||
as usize,
|
||||
));
|
||||
|
||||
// Draw!
|
||||
let is_proc_widget_grouped = proc_widget_state.is_grouped;
|
||||
let process_rows = sliced_vec.iter().map(|process| {
|
||||
let stringified_process_vec: Vec<String> = vec![
|
||||
if proc_widget_state.is_grouped {
|
||||
process.group_pids.len().to_string()
|
||||
} else {
|
||||
process.pid.to_string()
|
||||
},
|
||||
process.name.clone(),
|
||||
format!("{:.1}%", process.cpu_usage),
|
||||
format!("{:.1}%", process.mem_usage),
|
||||
process.read_per_sec.to_string(),
|
||||
process.write_per_sec.to_string(),
|
||||
process.total_read.to_string(),
|
||||
process.total_write.to_string(),
|
||||
process.process_states.to_string(),
|
||||
];
|
||||
Row::StyledData(
|
||||
stringified_process_vec.into_iter(),
|
||||
if is_on_widget {
|
||||
if process_counter as u64
|
||||
== proc_widget_state.scroll_state.current_scroll_position
|
||||
- start_position
|
||||
{
|
||||
process_counter = -1;
|
||||
self.colours.currently_selected_text_style
|
||||
Row::Data(
|
||||
vec![
|
||||
if is_proc_widget_grouped {
|
||||
process.group_pids.len().to_string()
|
||||
} else {
|
||||
if process_counter >= 0 {
|
||||
process_counter += 1;
|
||||
}
|
||||
self.colours.text_style
|
||||
}
|
||||
} else {
|
||||
self.colours.text_style
|
||||
},
|
||||
process.pid.to_string()
|
||||
},
|
||||
process.name.clone(),
|
||||
format!("{:.1}%", process.cpu_usage),
|
||||
format!("{:.1}%", process.mem_usage),
|
||||
process.read_per_sec.to_string(),
|
||||
process.write_per_sec.to_string(),
|
||||
process.total_read.to_string(),
|
||||
process.total_write.to_string(),
|
||||
process.process_states.to_string(),
|
||||
]
|
||||
.into_iter(),
|
||||
)
|
||||
});
|
||||
|
||||
|
@ -223,10 +212,13 @@ impl ProcessTableWidget for Painter {
|
|||
String::default()
|
||||
};
|
||||
|
||||
let border_and_title_style = if is_on_widget {
|
||||
self.colours.highlighted_border_style
|
||||
let (border_and_title_style, highlight_style) = if is_on_widget {
|
||||
(
|
||||
self.colours.highlighted_border_style,
|
||||
self.colours.currently_selected_text_style,
|
||||
)
|
||||
} else {
|
||||
self.colours.border_style
|
||||
(self.colours.border_style, self.colours.text_style)
|
||||
};
|
||||
|
||||
let process_block = if draw_border {
|
||||
|
@ -253,10 +245,12 @@ impl ProcessTableWidget for Painter {
|
|||
.direction(Direction::Horizontal)
|
||||
.split(draw_loc);
|
||||
|
||||
f.render_widget(
|
||||
f.render_stateful_widget(
|
||||
Table::new(process_headers.iter(), process_rows)
|
||||
.block(process_block)
|
||||
.header_style(self.colours.table_header_style)
|
||||
.highlight_style(highlight_style)
|
||||
.style(self.colours.text_style)
|
||||
.widths(
|
||||
&(intrinsic_widths
|
||||
.iter()
|
||||
|
@ -267,6 +261,7 @@ impl ProcessTableWidget for Painter {
|
|||
)
|
||||
.header_gap(app_state.app_config_fields.table_gap),
|
||||
margined_draw_loc[0],
|
||||
proc_table_state,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ impl TempTableWidget for Painter {
|
|||
if let Some(temp_widget_state) = app_state.temp_state.widget_states.get_mut(&widget_id) {
|
||||
let temp_sensor_data: &mut [Vec<String>] = &mut app_state.canvas_data.temp_sensor_data;
|
||||
|
||||
let num_rows = max(0, i64::from(draw_loc.height) - 5) as u64;
|
||||
let num_rows = max(0, i64::from(draw_loc.height) - self.table_height_offset) as u64;
|
||||
let start_position = get_start_position(
|
||||
num_rows,
|
||||
&temp_widget_state.scroll_state.scroll_direction,
|
||||
|
@ -48,32 +48,14 @@ impl TempTableWidget for Painter {
|
|||
temp_widget_state.scroll_state.current_scroll_position,
|
||||
app_state.is_resized,
|
||||
);
|
||||
let is_on_widget = widget_id == app_state.current_widget.widget_id;
|
||||
let temp_table_state = &mut temp_widget_state.scroll_state.table_state;
|
||||
temp_table_state.select(Some(
|
||||
(temp_widget_state.scroll_state.current_scroll_position - start_position) as usize,
|
||||
));
|
||||
|
||||
let sliced_vec = &temp_sensor_data[start_position as usize..];
|
||||
let mut temp_row_counter: i64 = 0;
|
||||
let current_widget_id = app_state.current_widget.widget_id;
|
||||
|
||||
let temperature_rows = sliced_vec.iter().map(|temp_row| {
|
||||
Row::StyledData(
|
||||
temp_row.iter(),
|
||||
if current_widget_id == widget_id {
|
||||
if temp_row_counter as u64
|
||||
== temp_widget_state.scroll_state.current_scroll_position
|
||||
- start_position
|
||||
{
|
||||
temp_row_counter = -1;
|
||||
self.colours.currently_selected_text_style
|
||||
} else {
|
||||
if temp_row_counter >= 0 {
|
||||
temp_row_counter += 1;
|
||||
}
|
||||
self.colours.text_style
|
||||
}
|
||||
} else {
|
||||
self.colours.text_style
|
||||
},
|
||||
)
|
||||
});
|
||||
let temperature_rows = sliced_vec.iter().map(|temp_row| Row::Data(temp_row.iter()));
|
||||
|
||||
// Calculate widths
|
||||
let width = f64::from(draw_loc.width);
|
||||
|
@ -100,25 +82,22 @@ impl TempTableWidget for Painter {
|
|||
" Temperatures ".to_string()
|
||||
};
|
||||
|
||||
let (border_and_title_style, highlight_style) = if is_on_widget {
|
||||
(
|
||||
self.colours.highlighted_border_style,
|
||||
self.colours.currently_selected_text_style,
|
||||
)
|
||||
} else {
|
||||
(self.colours.border_style, self.colours.text_style)
|
||||
};
|
||||
|
||||
let temp_block = if draw_border {
|
||||
Block::default()
|
||||
.title(&title)
|
||||
.title_style(if app_state.is_expanded {
|
||||
if app_state.current_widget.widget_id == widget_id {
|
||||
self.colours.highlighted_border_style
|
||||
} else {
|
||||
self.colours.border_style
|
||||
}
|
||||
} else {
|
||||
self.colours.widget_title_style
|
||||
})
|
||||
.title_style(border_and_title_style)
|
||||
.borders(Borders::ALL)
|
||||
.border_style(if app_state.current_widget.widget_id == widget_id {
|
||||
self.colours.highlighted_border_style
|
||||
} else {
|
||||
self.colours.border_style
|
||||
})
|
||||
} else if app_state.current_widget.widget_id == widget_id {
|
||||
.border_style(border_and_title_style)
|
||||
} else if is_on_widget {
|
||||
Block::default()
|
||||
.borders(*SIDE_BORDERS)
|
||||
.border_style(self.colours.highlighted_border_style)
|
||||
|
@ -128,21 +107,17 @@ impl TempTableWidget for Painter {
|
|||
|
||||
let margined_draw_loc = Layout::default()
|
||||
.constraints([Constraint::Percentage(100)].as_ref())
|
||||
.horizontal_margin(
|
||||
if app_state.current_widget.widget_id == widget_id || draw_border {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
},
|
||||
)
|
||||
.horizontal_margin(if is_on_widget || draw_border { 0 } else { 1 })
|
||||
.direction(Direction::Horizontal)
|
||||
.split(draw_loc);
|
||||
|
||||
// Draw
|
||||
f.render_widget(
|
||||
f.render_stateful_widget(
|
||||
Table::new(TEMP_HEADERS.iter(), temperature_rows)
|
||||
.block(temp_block)
|
||||
.header_style(self.colours.table_header_style)
|
||||
.highlight_style(highlight_style)
|
||||
.style(self.colours.text_style)
|
||||
.widths(
|
||||
&(intrinsic_widths
|
||||
.iter()
|
||||
|
@ -151,6 +126,7 @@ impl TempTableWidget for Painter {
|
|||
)
|
||||
.header_gap(app_state.app_config_fields.table_gap),
|
||||
margined_draw_loc[0],
|
||||
temp_table_state,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -151,7 +151,10 @@ pub const DEFAULT_CONFIG_CONTENT: &str = r##"
|
|||
#basic = false
|
||||
|
||||
# Use the old network legend style
|
||||
#use_old_network_legend = true
|
||||
#use_old_network_legend = false
|
||||
|
||||
# Remove space in tables
|
||||
#hide_table_gap = false
|
||||
|
||||
##########################################################
|
||||
|
||||
|
|
|
@ -145,7 +145,7 @@ fn main() -> error::Result<()> {
|
|||
app.used_widgets.clone(),
|
||||
);
|
||||
|
||||
let mut painter = canvas::Painter::init(widget_layout);
|
||||
let mut painter = canvas::Painter::init(widget_layout, app.app_config_fields.table_gap);
|
||||
if let Err(config_check) = generate_config_colours(&config, &mut painter) {
|
||||
cleanup_terminal(&mut terminal)?;
|
||||
return Err(config_check);
|
||||
|
|
Loading…
Reference in a new issue