Added maximizing mode to allow users to zoom into a particular widget. Not 100% done.

This commit is contained in:
ClementTsang 2020-02-11 21:16:43 -05:00
parent 908960f783
commit f0dad8f5bf
7 changed files with 447 additions and 195 deletions

View file

@ -22,6 +22,10 @@ Features of bottom include:
- Temperature widget to monitor detected sensors in your system.
- Config file support for custom colours and default options.
- Maximizing of widgets of interest.
The compatibility of each widget and operating systems are, as of version 0.1.0, as follows:
| OS | CPU | Memory | Disks | Temperature | Processes | Networks |
@ -137,10 +141,12 @@ Run using `btm`.
- `Ctrl/Shift-Arrow` or `H/J/K/L` to navigate between widgets. **Note that on macOS, `Ctrl`-arrow keys conflicts with an existing macOS binding, use `Shift`-arrow key instead.**
- `Esc` to close a dialog window.
- `Esc` to close a dialog window or exit maximized mode.
- `?` to get a help screen explaining the controls. Note all controls except `Esc` to close the dialog will be disabled while this is open.
- `Enter` on a widget to maximize the widget.
#### Scrollable Tables
- `Up` or `k` and `Down` or `j` scrolls through the list if the widget is a table (Temperature, Disks, Processes).

View file

@ -33,17 +33,31 @@ lazy_static! {
regex::Regex::new(".*");
}
/// AppConfigFields is meant to cover basic fields that would normally be set
/// by config files or launch options. Don't need to be mutable (set and forget).
pub struct AppConfigFields {
pub update_rate_in_milliseconds: u64,
pub temperature_type: temperature::TemperatureType,
pub use_dot: bool,
/// AppScrollWidgetState deals with fields for a scrollable app's current state.
#[derive(Default)]
pub struct AppScrollWidgetState {
pub current_scroll_position: u64,
pub previous_scroll_position: u64,
}
/// AppScrollWidgetState deals with fields for a scrollable app's current state.
pub struct AppScrollWidgetState {
pub widget_scroll_position: i64,
pub struct AppScrollState {
pub scroll_direction: ScrollDirection,
pub process_scroll_state: AppScrollWidgetState,
pub disk_scroll_state: AppScrollWidgetState,
pub temp_scroll_state: AppScrollWidgetState,
pub cpu_scroll_state: AppScrollWidgetState,
}
impl Default for AppScrollState {
fn default() -> Self {
AppScrollState {
scroll_direction: ScrollDirection::DOWN,
process_scroll_state: AppScrollWidgetState::default(),
disk_scroll_state: AppScrollWidgetState::default(),
temp_scroll_state: AppScrollWidgetState::default(),
cpu_scroll_state: AppScrollWidgetState::default(),
}
}
}
/// AppSearchState only deals with the search's current settings and state.
@ -131,35 +145,29 @@ impl Default for AppHelpDialogState {
}
}
// TODO: [OPT] Group like fields together... this is kinda gross to step through
/// AppConfigFields is meant to cover basic fields that would normally be set
/// by config files or launch options. Don't need to be mutable (set and forget).
pub struct AppConfigFields {
pub update_rate_in_milliseconds: u64,
pub temperature_type: temperature::TemperatureType,
pub use_dot: bool,
pub left_legend: bool,
pub show_average_cpu: bool,
pub use_current_cpu_total: bool,
}
pub struct App {
// Sorting
pub process_sorting_type: processes::ProcessSorting,
pub process_sorting_reverse: bool,
pub update_process_gui: bool,
// Positioning
pub scroll_direction: ScrollDirection,
pub currently_selected_process_position: u64,
pub currently_selected_disk_position: u64,
pub currently_selected_temperature_position: u64,
pub currently_selected_cpu_table_position: u64,
pub previous_disk_position: u64,
pub previous_temp_position: u64,
pub previous_process_position: u64,
pub previous_cpu_table_position: u64,
pub temperature_type: temperature::TemperatureType,
pub update_rate_in_milliseconds: u64,
pub show_average_cpu: bool,
pub app_scroll_positions: AppScrollState,
pub current_widget_selected: WidgetPosition,
pub data: data_harvester::Data,
awaiting_second_char: bool,
second_char: char,
pub use_dot: bool,
second_char: Option<char>,
pub dd_err: Option<String>,
to_delete_process_list: Option<(String, Vec<u32>)>,
pub is_frozen: bool,
pub left_legend: bool,
pub use_current_cpu_total: bool,
last_key_press: Instant,
pub canvas_data: canvas::DisplayableData,
enable_grouping: bool,
@ -168,6 +176,8 @@ pub struct App {
pub search_state: AppSearchState,
pub delete_dialog_state: AppDeleteDialogState,
pub help_dialog_state: AppHelpDialogState,
pub app_config_fields: AppConfigFields,
pub is_expanded: bool,
}
impl App {
@ -180,28 +190,14 @@ impl App {
process_sorting_type: processes::ProcessSorting::CPU,
process_sorting_reverse: true,
update_process_gui: false,
temperature_type,
update_rate_in_milliseconds,
show_average_cpu,
current_widget_selected: WidgetPosition::Process,
scroll_direction: ScrollDirection::DOWN,
currently_selected_process_position: 0,
currently_selected_disk_position: 0,
currently_selected_temperature_position: 0,
currently_selected_cpu_table_position: 0,
previous_process_position: 0,
previous_disk_position: 0,
previous_temp_position: 0,
previous_cpu_table_position: 0,
app_scroll_positions: AppScrollState::default(),
data: data_harvester::Data::default(),
awaiting_second_char: false,
second_char: ' ',
use_dot,
second_char: None,
dd_err: None,
to_delete_process_list: None,
is_frozen: false,
left_legend,
use_current_cpu_total,
last_key_press: Instant::now(),
canvas_data: canvas::DisplayableData::default(),
enable_grouping: false,
@ -210,6 +206,15 @@ impl App {
search_state: AppSearchState::default(),
delete_dialog_state: AppDeleteDialogState::default(),
help_dialog_state: AppHelpDialogState::default(),
app_config_fields: AppConfigFields {
show_average_cpu,
temperature_type,
use_dot,
update_rate_in_milliseconds,
left_legend,
use_current_cpu_total,
},
is_expanded: false,
}
}
@ -239,12 +244,14 @@ impl App {
} else if self.enable_searching {
self.current_widget_selected = WidgetPosition::Process;
self.enable_searching = false;
} else if self.is_expanded {
self.is_expanded = false;
}
}
fn reset_multi_tap_keys(&mut self) {
self.awaiting_second_char = false;
self.second_char = ' ';
self.second_char = None;
}
fn is_in_dialog(&self) -> bool {
@ -354,8 +361,12 @@ impl App {
regex::Regex::new(&final_regex_string)
};
self.previous_process_position = 0;
self.currently_selected_process_position = 0;
self.app_scroll_positions
.process_scroll_state
.previous_scroll_position = 0;
self.app_scroll_positions
.process_scroll_state
.current_scroll_position = 0;
}
pub fn get_cursor_position(&self) -> usize {
@ -364,22 +375,27 @@ impl App {
/// One of two functions allowed to run while in a dialog...
pub fn on_enter(&mut self) {
if self.delete_dialog_state.is_showing_dd && self.delete_dialog_state.is_on_yes {
// If within dd...
if self.dd_err.is_none() {
// Also ensure that we didn't just fail a dd...
let dd_result = self.kill_highlighted_process();
self.delete_dialog_state.is_on_yes = false;
if self.delete_dialog_state.is_showing_dd {
if self.delete_dialog_state.is_on_yes {
// If within dd...
if self.dd_err.is_none() {
// Also ensure that we didn't just fail a dd...
let dd_result = self.kill_highlighted_process();
self.delete_dialog_state.is_on_yes = false;
// Check if there was an issue... if so, inform the user.
if let Err(dd_err) = dd_result {
self.dd_err = Some(dd_err.to_string());
} else {
self.delete_dialog_state.is_showing_dd = false;
// Check if there was an issue... if so, inform the user.
if let Err(dd_err) = dd_result {
self.dd_err = Some(dd_err.to_string());
} else {
self.delete_dialog_state.is_showing_dd = false;
}
}
} else {
self.delete_dialog_state.is_showing_dd = false;
}
} else {
self.delete_dialog_state.is_showing_dd = false;
} else if !self.is_in_dialog() {
// Pop-out mode.
self.is_expanded = true;
}
}
@ -490,55 +506,79 @@ impl App {
}
'd' => {
if let WidgetPosition::Process = self.current_widget_selected {
if self.awaiting_second_char && self.second_char == 'd' {
self.awaiting_second_char = false;
self.second_char = ' ';
let mut is_first_d = true;
if let Some(second_char) = self.second_char {
if self.awaiting_second_char && second_char == 'd' {
is_first_d = false;
self.awaiting_second_char = false;
self.second_char = None;
if self.currently_selected_process_position
< self.canvas_data.finalized_process_data.len() as u64
{
let current_process = if self.is_grouped() {
let group_pids = &self.canvas_data.finalized_process_data
[self.currently_selected_process_position as usize]
.group_pids;
if self
.app_scroll_positions
.process_scroll_state
.current_scroll_position < self
.canvas_data
.finalized_process_data
.len() as u64
{
let current_process = if self.is_grouped() {
let group_pids = &self
.canvas_data
.finalized_process_data[self
.app_scroll_positions
.process_scroll_state
.current_scroll_position as usize]
.group_pids;
let mut ret = ("".to_string(), group_pids.clone());
let mut ret = ("".to_string(), group_pids.clone());
for pid in group_pids {
if let Some(process) =
self.canvas_data.process_data.get(&pid)
{
ret.0 = process.name.clone();
break;
for pid in group_pids {
if let Some(process) =
self.canvas_data.process_data.get(&pid)
{
ret.0 = process.name.clone();
break;
}
}
}
ret
} else {
let process = self.canvas_data.finalized_process_data
[self.currently_selected_process_position as usize]
.clone();
(process.name.clone(), vec![process.pid])
};
ret
} else {
let process = self.canvas_data.finalized_process_data
[self
.app_scroll_positions
.process_scroll_state
.current_scroll_position as usize]
.clone();
(process.name.clone(), vec![process.pid])
};
self.to_delete_process_list = Some(current_process);
self.delete_dialog_state.is_showing_dd = true;
self.to_delete_process_list = Some(current_process);
self.delete_dialog_state.is_showing_dd = true;
}
self.reset_multi_tap_keys();
}
}
self.reset_multi_tap_keys();
} else {
if is_first_d {
self.awaiting_second_char = true;
self.second_char = 'd';
self.second_char = Some('d');
}
}
}
'g' => {
if self.awaiting_second_char && self.second_char == 'g' {
self.awaiting_second_char = false;
self.second_char = ' ';
self.skip_to_first();
} else {
let mut is_first_g = true;
if let Some(second_char) = self.second_char {
if self.awaiting_second_char && second_char == 'g' {
is_first_g = false;
self.awaiting_second_char = false;
self.second_char = None;
self.skip_to_first();
}
}
if is_first_g {
self.awaiting_second_char = true;
self.second_char = 'g';
self.second_char = Some('g');
}
}
'G' => self.skip_to_last(),
@ -558,7 +598,9 @@ impl App {
}
}
self.update_process_gui = true;
self.currently_selected_process_position = 0;
self.app_scroll_positions
.process_scroll_state
.current_scroll_position = 0;
}
'm' => {
match self.process_sorting_type {
@ -571,7 +613,9 @@ impl App {
}
}
self.update_process_gui = true;
self.currently_selected_process_position = 0;
self.app_scroll_positions
.process_scroll_state
.current_scroll_position = 0;
}
'p' => {
// Disable if grouping
@ -586,7 +630,9 @@ impl App {
}
}
self.update_process_gui = true;
self.currently_selected_process_position = 0;
self.app_scroll_positions
.process_scroll_state
.current_scroll_position = 0;
}
}
'n' => {
@ -600,15 +646,20 @@ impl App {
}
}
self.update_process_gui = true;
self.currently_selected_process_position = 0;
self.app_scroll_positions
.process_scroll_state
.current_scroll_position = 0;
}
'?' => {
self.help_dialog_state.is_showing_help = true;
}
_ => {}
}
if self.awaiting_second_char && caught_char != self.second_char {
self.awaiting_second_char = false;
if let Some(second_char) = self.second_char {
if self.awaiting_second_char && caught_char != second_char {
self.awaiting_second_char = false;
}
}
}
} else if self.help_dialog_state.is_showing_help {
@ -648,8 +699,8 @@ impl App {
// Network -(up)> MEM, -(right)> PROC
// PROC -(up)> Disk, -(down)> PROC_SEARCH, -(left)> Network
// PROC_SEARCH -(up)> PROC, -(left)> Network
pub fn move_left(&mut self) {
if !self.is_in_dialog() {
pub fn move_widget_selection_left(&mut self) {
if !self.is_in_dialog() && !self.is_expanded {
self.current_widget_selected = match self.current_widget_selected {
WidgetPosition::Process => WidgetPosition::Network,
WidgetPosition::ProcessSearch => WidgetPosition::Network,
@ -657,23 +708,25 @@ impl App {
WidgetPosition::Temp => WidgetPosition::Mem,
_ => self.current_widget_selected,
};
self.reset_multi_tap_keys();
}
self.reset_multi_tap_keys();
}
pub fn move_right(&mut self) {
if !self.is_in_dialog() {
pub fn move_widget_selection_right(&mut self) {
if !self.is_in_dialog() && !self.is_expanded {
self.current_widget_selected = match self.current_widget_selected {
WidgetPosition::Mem => WidgetPosition::Temp,
WidgetPosition::Network => WidgetPosition::Process,
_ => self.current_widget_selected,
};
self.reset_multi_tap_keys();
}
self.reset_multi_tap_keys();
}
pub fn move_up(&mut self) {
if !self.is_in_dialog() {
pub fn move_widget_selection_up(&mut self) {
if !self.is_in_dialog() && !self.is_expanded {
self.current_widget_selected = match self.current_widget_selected {
WidgetPosition::Mem => WidgetPosition::Cpu,
WidgetPosition::Network => WidgetPosition::Mem,
@ -683,12 +736,18 @@ impl App {
WidgetPosition::Disk => WidgetPosition::Temp,
_ => self.current_widget_selected,
};
self.reset_multi_tap_keys();
} else if self.is_expanded {
self.current_widget_selected = match self.current_widget_selected {
WidgetPosition::ProcessSearch => WidgetPosition::Process,
_ => self.current_widget_selected,
};
}
self.reset_multi_tap_keys();
}
pub fn move_down(&mut self) {
if !self.is_in_dialog() {
pub fn move_widget_selection_down(&mut self) {
if !self.is_in_dialog() && !self.is_expanded {
self.current_widget_selected = match self.current_widget_selected {
WidgetPosition::Cpu => WidgetPosition::Mem,
WidgetPosition::Mem => WidgetPosition::Network,
@ -703,21 +762,49 @@ impl App {
}
_ => self.current_widget_selected,
};
self.reset_multi_tap_keys();
} else if self.is_expanded {
self.current_widget_selected = match self.current_widget_selected {
WidgetPosition::Process => {
if self.is_searching() {
WidgetPosition::ProcessSearch
} else {
WidgetPosition::Process
}
}
_ => self.current_widget_selected,
};
}
self.reset_multi_tap_keys();
}
pub fn skip_to_first(&mut self) {
if !self.is_in_dialog() {
match self.current_widget_selected {
WidgetPosition::Process => self.currently_selected_process_position = 0,
WidgetPosition::Temp => self.currently_selected_temperature_position = 0,
WidgetPosition::Disk => self.currently_selected_disk_position = 0,
WidgetPosition::Cpu => self.currently_selected_cpu_table_position = 0,
WidgetPosition::Process => {
self.app_scroll_positions
.process_scroll_state
.current_scroll_position = 0
}
WidgetPosition::Temp => {
self.app_scroll_positions
.temp_scroll_state
.current_scroll_position = 0
}
WidgetPosition::Disk => {
self.app_scroll_positions
.disk_scroll_state
.current_scroll_position = 0
}
WidgetPosition::Cpu => {
self.app_scroll_positions
.cpu_scroll_state
.current_scroll_position = 0
}
_ => {}
}
self.scroll_direction = ScrollDirection::UP;
self.app_scroll_positions.scroll_direction = ScrollDirection::UP;
self.reset_multi_tap_keys();
}
}
@ -726,24 +813,28 @@ impl App {
if !self.is_in_dialog() {
match self.current_widget_selected {
WidgetPosition::Process => {
self.currently_selected_process_position =
self.canvas_data.finalized_process_data.len() as u64 - 1
self.app_scroll_positions
.process_scroll_state
.current_scroll_position = self.canvas_data.finalized_process_data.len() as u64 - 1
}
WidgetPosition::Temp => {
self.currently_selected_temperature_position =
self.canvas_data.temp_sensor_data.len() as u64 - 1
self.app_scroll_positions
.temp_scroll_state
.current_scroll_position = self.canvas_data.temp_sensor_data.len() as u64 - 1
}
WidgetPosition::Disk => {
self.currently_selected_disk_position =
self.canvas_data.disk_data.len() as u64 - 1
self.app_scroll_positions
.disk_scroll_state
.current_scroll_position = self.canvas_data.disk_data.len() as u64 - 1
}
WidgetPosition::Cpu => {
self.currently_selected_cpu_table_position =
self.canvas_data.cpu_data.len() as u64 - 1;
self.app_scroll_positions
.cpu_scroll_state
.current_scroll_position = self.canvas_data.cpu_data.len() as u64 - 1;
}
_ => {}
}
self.scroll_direction = ScrollDirection::DOWN;
self.app_scroll_positions.scroll_direction = ScrollDirection::DOWN;
self.reset_multi_tap_keys();
}
}
@ -757,7 +848,7 @@ impl App {
WidgetPosition::Cpu => self.change_cpu_table_position(-1), // TODO: [PO?] Temporary, may change if we add scaling
_ => {}
}
self.scroll_direction = ScrollDirection::UP;
self.app_scroll_positions.scroll_direction = ScrollDirection::UP;
self.reset_multi_tap_keys();
}
}
@ -771,48 +862,70 @@ impl App {
WidgetPosition::Cpu => self.change_cpu_table_position(1), // TODO: [PO?] Temporary, may change if we add scaling
_ => {}
}
self.scroll_direction = ScrollDirection::DOWN;
self.app_scroll_positions.scroll_direction = ScrollDirection::DOWN;
self.reset_multi_tap_keys();
}
}
fn change_cpu_table_position(&mut self, num_to_change_by: i64) {
if self.currently_selected_cpu_table_position as i64 + num_to_change_by >= 0
&& self.currently_selected_cpu_table_position as i64 + num_to_change_by
< self.canvas_data.cpu_data.len() as i64
let current_posn = self
.app_scroll_positions
.cpu_scroll_state
.current_scroll_position;
if current_posn as i64 + num_to_change_by >= 0
&& current_posn as i64 + num_to_change_by < self.canvas_data.cpu_data.len() as i64
{
self.currently_selected_cpu_table_position =
(self.currently_selected_cpu_table_position as i64 + num_to_change_by) as u64;
self.app_scroll_positions
.cpu_scroll_state
.current_scroll_position = (current_posn as i64 + num_to_change_by) as u64;
}
}
fn change_process_position(&mut self, num_to_change_by: i64) {
if self.currently_selected_process_position as i64 + num_to_change_by >= 0
&& self.currently_selected_process_position as i64 + num_to_change_by
let current_posn = self
.app_scroll_positions
.process_scroll_state
.current_scroll_position;
if current_posn as i64 + num_to_change_by >= 0
&& current_posn as i64 + num_to_change_by
< self.canvas_data.finalized_process_data.len() as i64
{
self.currently_selected_process_position =
(self.currently_selected_process_position as i64 + num_to_change_by) as u64;
self.app_scroll_positions
.process_scroll_state
.current_scroll_position = (current_posn as i64 + num_to_change_by) as u64;
}
}
fn change_temp_position(&mut self, num_to_change_by: i64) {
if self.currently_selected_temperature_position as i64 + num_to_change_by >= 0
&& self.currently_selected_temperature_position as i64 + num_to_change_by
let current_posn = self
.app_scroll_positions
.temp_scroll_state
.current_scroll_position;
if current_posn as i64 + num_to_change_by >= 0
&& current_posn as i64 + num_to_change_by
< self.canvas_data.temp_sensor_data.len() as i64
{
self.currently_selected_temperature_position =
(self.currently_selected_temperature_position as i64 + num_to_change_by) as u64;
self.app_scroll_positions
.temp_scroll_state
.current_scroll_position = (current_posn as i64 + num_to_change_by) as u64;
}
}
fn change_disk_position(&mut self, num_to_change_by: i64) {
if self.currently_selected_disk_position as i64 + num_to_change_by >= 0
&& self.currently_selected_disk_position as i64 + num_to_change_by
< self.canvas_data.disk_data.len() as i64
let current_posn = self
.app_scroll_positions
.disk_scroll_state
.current_scroll_position;
if current_posn as i64 + num_to_change_by >= 0
&& current_posn as i64 + num_to_change_by < self.canvas_data.disk_data.len() as i64
{
self.currently_selected_disk_position =
(self.currently_selected_disk_position as i64 + num_to_change_by) as u64;
self.app_scroll_positions
.disk_scroll_state
.current_scroll_position = (current_posn as i64 + num_to_change_by) as u64;
}
}
}

View file

@ -115,6 +115,8 @@ impl DataState {
let current_instant = std::time::Instant::now();
// TODO: [OPT] MT/Async the harvesting step.
// Network
self.data.network = network::get_network_data(
&self.sys,

View file

@ -1,5 +1,5 @@
use crate::{
app::{self, data_harvester::processes::ProcessHarvest},
app::{self, data_harvester::processes::ProcessHarvest, WidgetPosition},
constants::*,
data_conversion::{ConvertedCpuData, ConvertedProcessData},
utils::error,
@ -146,9 +146,9 @@ impl Painter {
.margin(1)
.constraints(
[
Constraint::Percentage(32),
Constraint::Percentage(36),
Constraint::Percentage(32),
Constraint::Percentage(30),
Constraint::Percentage(40),
Constraint::Percentage(30),
]
.as_ref(),
)
@ -319,6 +319,72 @@ impl Painter {
// This is a bit nasty, but it works well... I guess.
app_state.delete_dialog_state.is_showing_dd = false;
}
} else if app_state.is_expanded {
// TODO: [REF] we should combine this with normal drawing tbh
let rect = Layout::default()
.margin(1)
.constraints([Constraint::Percentage(100)].as_ref())
.split(f.size());
match &app_state.current_widget_selected {
WidgetPosition::Cpu => {
let cpu_chunk = Layout::default()
.direction(Direction::Horizontal)
.margin(0)
.constraints(
if app_state.app_config_fields.left_legend {
[Constraint::Percentage(15), Constraint::Percentage(85)]
} else {
[Constraint::Percentage(85), Constraint::Percentage(15)]
}
.as_ref(),
)
.split(rect[0]);
let legend_index = if app_state.app_config_fields.left_legend {
0
} else {
1
};
let graph_index = if app_state.app_config_fields.left_legend {
1
} else {
0
};
self.draw_cpu_graph(&mut f, &app_state, cpu_chunk[graph_index]);
self.draw_cpu_legend(&mut f, app_state, cpu_chunk[legend_index]);
}
WidgetPosition::Mem => {
self.draw_memory_graph(&mut f, &app_state, rect[0]);
}
WidgetPosition::Disk => {
self.draw_disk_table(&mut f, app_state, rect[0]);
}
WidgetPosition::Temp => {
self.draw_temp_table(&mut f, app_state, rect[0]);
}
WidgetPosition::Network => {
self.draw_network_graph(&mut f, &app_state, rect[0]);
}
WidgetPosition::Process | WidgetPosition::ProcessSearch => {
if app_state.is_searching() {
let processes_chunk = Layout::default()
.direction(Direction::Vertical)
.margin(0)
.constraints(
[Constraint::Percentage(85), Constraint::Percentage(15)]
.as_ref(),
)
.split(rect[0]);
self.draw_processes_table(&mut f, app_state, processes_chunk[0]);
self.draw_search_field(&mut f, app_state, processes_chunk[1]);
} else {
self.draw_processes_table(&mut f, app_state, rect[0]);
}
}
}
} else {
// TODO: [TUI] Change this back to a more even 33/33/34 when TUI releases
let vertical_chunks = Layout::default()
@ -357,7 +423,7 @@ impl Painter {
.direction(Direction::Horizontal)
.margin(0)
.constraints(
if app_state.left_legend {
if app_state.app_config_fields.left_legend {
[Constraint::Percentage(15), Constraint::Percentage(85)]
} else {
[Constraint::Percentage(85), Constraint::Percentage(15)]
@ -386,8 +452,16 @@ impl Painter {
.split(bottom_chunks[0]);
// Default chunk index based on left or right legend setting
let legend_index = if app_state.left_legend { 0 } else { 1 };
let graph_index = if app_state.left_legend { 1 } else { 0 };
let legend_index = if app_state.app_config_fields.left_legend {
0
} else {
1
};
let graph_index = if app_state.app_config_fields.left_legend {
1
} else {
0
};
// Set up blocks and their components
// CPU graph
@ -468,7 +542,7 @@ impl Painter {
));
}
if app_state.show_average_cpu {
if app_state.app_config_fields.show_average_cpu {
if let Some(avg_cpu_entry) = cpu_data.first() {
cpu_entries_vec.push((
self.colours.cpu_colour_styles[0],
@ -484,7 +558,7 @@ impl Painter {
for cpu_entry in &cpu_entries_vec {
dataset_vector.push(
Dataset::default()
.marker(if app_state.use_dot {
.marker(if app_state.app_config_fields.use_dot {
Marker::Dot
} else {
Marker::Braille
@ -519,9 +593,15 @@ impl Painter {
let num_rows = max(0, i64::from(draw_loc.height) - 5) as u64;
let start_position = get_start_position(
num_rows,
&(app_state.scroll_direction),
&mut app_state.previous_cpu_table_position,
app_state.currently_selected_cpu_table_position,
&(app_state.app_scroll_positions.scroll_direction),
&mut app_state
.app_scroll_positions
.cpu_scroll_state
.previous_scroll_position,
app_state
.app_scroll_positions
.cpu_scroll_state
.current_scroll_position,
);
let sliced_cpu_data = &cpu_data[start_position as usize..];
@ -547,7 +627,10 @@ impl Painter {
match app_state.current_widget_selected {
app::WidgetPosition::Cpu => {
if cpu_row_counter as u64
== app_state.currently_selected_cpu_table_position - start_position
== app_state
.app_scroll_positions
.cpu_scroll_state
.current_scroll_position - start_position
{
cpu_row_counter = -1;
self.colours.currently_selected_text_style
@ -612,7 +695,7 @@ impl Painter {
let mut mem_canvas_vec: Vec<Dataset> = vec![Dataset::default()
.name(&app_state.canvas_data.mem_label)
.marker(if app_state.use_dot {
.marker(if app_state.app_config_fields.use_dot {
Marker::Dot
} else {
Marker::Braille
@ -624,7 +707,7 @@ impl Painter {
mem_canvas_vec.push(
Dataset::default()
.name(&app_state.canvas_data.swap_label)
.marker(if app_state.use_dot {
.marker(if app_state.app_config_fields.use_dot {
Marker::Dot
} else {
Marker::Braille
@ -682,7 +765,7 @@ impl Painter {
"RX: {:7}",
app_state.canvas_data.rx_display.clone()
))
.marker(if app_state.use_dot {
.marker(if app_state.app_config_fields.use_dot {
Marker::Dot
} else {
Marker::Braille
@ -694,13 +777,21 @@ impl Painter {
"TX: {:7}",
app_state.canvas_data.tx_display.clone()
))
.marker(if app_state.use_dot {
.marker(if app_state.app_config_fields.use_dot {
Marker::Dot
} else {
Marker::Braille
})
.style(self.colours.tx_style)
.data(&network_data_tx),
Dataset::default().name(&format!(
"Total RX: {:7}",
app_state.canvas_data.total_rx_display.clone()
)),
Dataset::default().name(&format!(
"Total TX: {:7}",
app_state.canvas_data.total_tx_display.clone()
)),
])
.render(f, draw_loc);
}
@ -763,9 +854,15 @@ impl Painter {
let num_rows = max(0, i64::from(draw_loc.height) - 5) as u64;
let start_position = get_start_position(
num_rows,
&(app_state.scroll_direction),
&mut app_state.previous_temp_position,
app_state.currently_selected_temperature_position,
&(app_state.app_scroll_positions.scroll_direction),
&mut app_state
.app_scroll_positions
.temp_scroll_state
.previous_scroll_position,
app_state
.app_scroll_positions
.temp_scroll_state
.current_scroll_position,
);
let sliced_vec = &(temp_sensor_data[start_position as usize..]);
@ -777,7 +874,10 @@ impl Painter {
match app_state.current_widget_selected {
app::WidgetPosition::Temp => {
if temp_row_counter as u64
== app_state.currently_selected_temperature_position - start_position
== app_state
.app_scroll_positions
.temp_scroll_state
.current_scroll_position - start_position
{
temp_row_counter = -1;
self.colours.currently_selected_text_style
@ -829,9 +929,15 @@ impl Painter {
let num_rows = max(0, i64::from(draw_loc.height) - 5) as u64;
let start_position = get_start_position(
num_rows,
&(app_state.scroll_direction),
&mut app_state.previous_disk_position,
app_state.currently_selected_disk_position,
&(app_state.app_scroll_positions.scroll_direction),
&mut app_state
.app_scroll_positions
.disk_scroll_state
.previous_scroll_position,
app_state
.app_scroll_positions
.disk_scroll_state
.current_scroll_position,
);
let sliced_vec = &disk_data[start_position as usize..];
@ -843,7 +949,10 @@ impl Painter {
match app_state.current_widget_selected {
app::WidgetPosition::Disk => {
if disk_counter as u64
== app_state.currently_selected_disk_position - start_position
== app_state
.app_scroll_positions
.disk_scroll_state
.current_scroll_position - start_position
{
disk_counter = -1;
self.colours.currently_selected_text_style
@ -1029,9 +1138,15 @@ impl Painter {
let position = get_start_position(
num_rows,
&(app_state.scroll_direction),
&mut app_state.previous_process_position,
app_state.currently_selected_process_position,
&(app_state.app_scroll_positions.scroll_direction),
&mut app_state
.app_scroll_positions
.process_scroll_state
.previous_scroll_position,
app_state
.app_scroll_positions
.process_scroll_state
.current_scroll_position,
);
// Sanity check
@ -1061,7 +1176,10 @@ impl Painter {
match app_state.current_widget_selected {
app::WidgetPosition::Process => {
if process_counter as u64
== app_state.currently_selected_process_position - start_position
== app_state
.app_scroll_positions
.process_scroll_state
.current_scroll_position - start_position
{
process_counter = -1;
self.colours.currently_selected_text_style

View file

@ -12,7 +12,7 @@ pub const DEFAULT_UNIX_CONFIG_FILE_PATH: &str = "~/.config/btm/btm.toml";
pub const DEFAULT_WINDOWS_CONFIG_FILE_PATH: &str = "";
// Help text
pub const GENERAL_HELP_TEXT: [&str; 15] = [
pub const GENERAL_HELP_TEXT: [&str; 16] = [
"General Keybindings\n\n",
"Esc Close dialog box\n",
"q, Ctrl-c Quit bottom\n",
@ -28,6 +28,7 @@ pub const GENERAL_HELP_TEXT: [&str; 15] = [
"? Open the help screen\n",
"gg Skip to the first entry of a list\n",
"G Skip to the last entry of a list\n",
"Enter Maximize the currently selected widget\n",
];
pub const PROCESS_HELP_TEXT: [&str; 8] = [

View file

@ -62,7 +62,7 @@ pub fn convert_temp_row(app: &App) -> Vec<Vec<String>> {
let mut sensor_vector: Vec<Vec<String>> = Vec::new();
let current_data = &app.data_collection;
let temp_type = &app.temperature_type;
let temp_type = &app.app_config_fields.temperature_type;
if current_data.temp_harvest.is_empty() {
sensor_vector.push(vec!["No Sensors Found".to_string(), "".to_string()])

View file

@ -182,7 +182,7 @@ fn main() -> error::Result<()> {
rrx,
use_current_cpu_total,
update_rate_in_milliseconds as u64,
app.temperature_type.clone(),
app.app_config_fields.temperature_type.clone(),
);
let mut painter = canvas::Painter::default();
@ -214,6 +214,8 @@ fn main() -> error::Result<()> {
// Convert all data into tui-compliant components
// TODO: [OPT] MT the conversion step.
// Network
let network_data = convert_network_data_points(&app.data_collection);
app.canvas_data.network_data_rx = network_data.rx;
@ -236,8 +238,10 @@ fn main() -> error::Result<()> {
app.canvas_data.swap_label = memory_and_swap_labels.1;
// CPU
app.canvas_data.cpu_data =
convert_cpu_data_points(app.show_average_cpu, &app.data_collection);
app.canvas_data.cpu_data = convert_cpu_data_points(
app.app_config_fields.show_average_cpu,
&app.data_collection,
);
// Processes
let (single, grouped) = convert_process_data(&app.data_collection);
@ -294,10 +298,10 @@ fn handle_key_event_or_break(
KeyCode::Down => app.on_down_key(),
KeyCode::Left => app.on_left_key(),
KeyCode::Right => app.on_right_key(),
KeyCode::Char('H') => app.move_left(),
KeyCode::Char('L') => app.move_right(),
KeyCode::Char('K') => app.move_up(),
KeyCode::Char('J') => app.move_down(),
KeyCode::Char('H') => app.move_widget_selection_left(),
KeyCode::Char('L') => app.move_widget_selection_right(),
KeyCode::Char('K') => app.move_widget_selection_up(),
KeyCode::Char('J') => app.move_widget_selection_down(),
KeyCode::Char(character) => app.on_char_key(character),
KeyCode::Esc => app.on_esc(),
KeyCode::Enter => app.on_enter(),
@ -314,10 +318,10 @@ fn handle_key_event_or_break(
match event.code {
KeyCode::Char('f') => app.enable_searching(),
KeyCode::Left => app.move_left(),
KeyCode::Right => app.move_right(),
KeyCode::Up => app.move_up(),
KeyCode::Down => app.move_down(),
KeyCode::Left => app.move_widget_selection_left(),
KeyCode::Right => app.move_widget_selection_right(),
KeyCode::Up => app.move_widget_selection_up(),
KeyCode::Down => app.move_widget_selection_down(),
KeyCode::Char('r') => {
if rtx.send(ResetEvent::Reset).is_ok() {
app.reset();
@ -329,10 +333,18 @@ fn handle_key_event_or_break(
}
} else if let KeyModifiers::SHIFT = event.modifiers {
match event.code {
KeyCode::Left | KeyCode::Char('h') | KeyCode::Char('H') => app.move_left(),
KeyCode::Right | KeyCode::Char('l') | KeyCode::Char('L') => app.move_right(),
KeyCode::Up | KeyCode::Char('k') | KeyCode::Char('K') => app.move_up(),
KeyCode::Down | KeyCode::Char('j') | KeyCode::Char('J') => app.move_down(),
KeyCode::Left | KeyCode::Char('h') | KeyCode::Char('H') => {
app.move_widget_selection_left()
}
KeyCode::Right | KeyCode::Char('l') | KeyCode::Char('L') => {
app.move_widget_selection_right()
}
KeyCode::Up | KeyCode::Char('k') | KeyCode::Char('K') => {
app.move_widget_selection_up()
}
KeyCode::Down | KeyCode::Char('j') | KeyCode::Char('J') => {
app.move_widget_selection_down()
}
KeyCode::Char('/') | KeyCode::Char('?') => app.on_char_key('?'),
_ => {}
}