refactor: Start state refactor

This commit is contained in:
ClementTsang 2021-05-23 18:51:35 -04:00
parent d1e672f263
commit f73ea0da36
36 changed files with 492 additions and 762 deletions

View File

@ -1,8 +1,14 @@
pub mod data_farmer;
pub mod data_harvester;
pub mod filter;
pub mod layout_manager;
mod process_killer;
pub mod query;
pub mod widget_states;
use std::{
cmp::{max, min},
collections::HashMap,
// io::Write,
path::PathBuf,
time::Instant,
};
@ -13,26 +19,17 @@ use typed_builder::*;
use data_farmer::*;
use data_harvester::{processes, temperature};
pub use filter::*;
use layout_manager::*;
pub use states::*;
pub use widget_states::*;
use crate::{
canvas, constants,
options::Config,
options::ConfigFlags,
options::WidgetIdEnabled,
units::data_units::DataUnit,
utils::error::{BottomError, Result},
Pid,
};
pub mod data_farmer;
pub mod data_harvester;
pub mod layout_manager;
mod process_killer;
pub mod query;
pub mod states;
const MAX_SEARCH_LENGTH: usize = 200;
#[derive(Debug, Clone)]
@ -68,23 +65,8 @@ pub struct AppConfigFields {
pub network_use_binary_prefix: bool,
}
/// For filtering out information
#[derive(Debug, Clone)]
pub struct DataFilters {
pub disk_filter: Option<Filter>,
pub mount_filter: Option<Filter>,
pub temp_filter: Option<Filter>,
pub net_filter: Option<Filter>,
}
#[derive(Debug, Clone)]
pub struct Filter {
pub is_list_ignored: bool,
pub list: Vec<regex::Regex>,
}
#[derive(TypedBuilder)]
pub struct App {
pub struct AppState {
#[builder(default = false, setter(skip))]
awaiting_second_char: bool,
@ -127,12 +109,6 @@ pub struct App {
#[builder(default = false, setter(skip))]
pub basic_mode_use_percent: bool,
#[builder(default = false, setter(skip))]
pub is_config_open: bool,
#[builder(default = false, setter(skip))]
pub did_config_fail_to_save: bool,
#[cfg(target_family = "unix")]
#[builder(default, setter(skip))]
pub user_table: processes::UserTable,
@ -150,8 +126,6 @@ pub struct App {
pub current_widget: BottomWidget,
pub used_widgets: UsedWidgets,
pub filters: DataFilters,
pub config: Config,
pub config_path: Option<PathBuf>,
}
#[cfg(target_os = "windows")]
@ -161,7 +135,7 @@ const MAX_SIGNAL: usize = 64;
#[cfg(target_os = "macos")]
const MAX_SIGNAL: usize = 31;
impl App {
impl AppState {
pub fn reset(&mut self) {
// Reset multi
self.reset_multi_tap_keys();
@ -218,8 +192,6 @@ impl App {
}
self.is_force_redraw = true;
} else if self.is_config_open {
self.close_config_screen();
} else {
match self.current_widget.widget_type {
BottomWidgetType::Proc => {
@ -297,7 +269,7 @@ impl App {
}
fn ignore_normal_keybinds(&self) -> bool {
self.is_config_open || self.is_in_dialog()
self.is_in_dialog()
}
pub fn on_tab(&mut self) {
@ -507,7 +479,6 @@ impl App {
pub fn toggle_ignore_case(&mut self) {
let is_in_search_widget = self.is_in_search_widget();
let mut is_case_sensitive: Option<bool> = None;
if let Some(proc_widget_state) = self
.proc_state
.widget_states
@ -519,50 +490,12 @@ impl App {
.search_toggle_ignore_case();
proc_widget_state.update_query();
self.proc_state.force_update = Some(self.current_widget.widget_id - 1);
// Remember, it's the opposite (ignoring case is case "in"sensitive)
is_case_sensitive = Some(!proc_widget_state.process_search_state.is_ignoring_case);
}
}
// Also toggle it in the config file if we actually changed it.
if let Some(is_ignoring_case) = is_case_sensitive {
if let Some(flags) = &mut self.config.flags {
if let Some(map) = &mut flags.search_case_enabled_widgets_map {
// Just update the map.
let mapping = map.entry(self.current_widget.widget_id - 1).or_default();
*mapping = is_ignoring_case;
flags.search_case_enabled_widgets =
Some(WidgetIdEnabled::create_from_hashmap(&map));
} else {
// Map doesn't exist yet... initialize ourselves.
let mut map = HashMap::default();
map.insert(self.current_widget.widget_id - 1, is_ignoring_case);
flags.search_case_enabled_widgets =
Some(WidgetIdEnabled::create_from_hashmap(&map));
flags.search_case_enabled_widgets_map = Some(map);
}
} else {
// Must initialize it ourselves...
let mut map = HashMap::default();
map.insert(self.current_widget.widget_id - 1, is_ignoring_case);
self.config.flags = Some(
ConfigFlags::builder()
.search_case_enabled_widgets(WidgetIdEnabled::create_from_hashmap(&map))
.search_case_enabled_widgets_map(map)
.build(),
);
}
// self.did_config_fail_to_save = self.update_config_file().is_err();
}
}
pub fn toggle_search_whole_word(&mut self) {
let is_in_search_widget = self.is_in_search_widget();
let mut is_searching_whole_word: Option<bool> = None;
if let Some(proc_widget_state) = self
.proc_state
.widget_states
@ -574,55 +507,12 @@ impl App {
.search_toggle_whole_word();
proc_widget_state.update_query();
self.proc_state.force_update = Some(self.current_widget.widget_id - 1);
is_searching_whole_word = Some(
proc_widget_state
.process_search_state
.is_searching_whole_word,
);
}
}
// Also toggle it in the config file if we actually changed it.
if let Some(is_searching_whole_word) = is_searching_whole_word {
if let Some(flags) = &mut self.config.flags {
if let Some(map) = &mut flags.search_whole_word_enabled_widgets_map {
// Just update the map.
let mapping = map.entry(self.current_widget.widget_id - 1).or_default();
*mapping = is_searching_whole_word;
flags.search_whole_word_enabled_widgets =
Some(WidgetIdEnabled::create_from_hashmap(&map));
} else {
// Map doesn't exist yet... initialize ourselves.
let mut map = HashMap::default();
map.insert(self.current_widget.widget_id - 1, is_searching_whole_word);
flags.search_whole_word_enabled_widgets =
Some(WidgetIdEnabled::create_from_hashmap(&map));
flags.search_whole_word_enabled_widgets_map = Some(map);
}
} else {
// Must initialize it ourselves...
let mut map = HashMap::default();
map.insert(self.current_widget.widget_id - 1, is_searching_whole_word);
self.config.flags = Some(
ConfigFlags::builder()
.search_whole_word_enabled_widgets(WidgetIdEnabled::create_from_hashmap(
&map,
))
.search_whole_word_enabled_widgets_map(map)
.build(),
);
}
// self.did_config_fail_to_save = self.update_config_file().is_err();
}
}
pub fn toggle_search_regex(&mut self) {
let is_in_search_widget = self.is_in_search_widget();
let mut is_searching_with_regex: Option<bool> = None;
if let Some(proc_widget_state) = self
.proc_state
.widget_states
@ -632,48 +522,8 @@ impl App {
proc_widget_state.process_search_state.search_toggle_regex();
proc_widget_state.update_query();
self.proc_state.force_update = Some(self.current_widget.widget_id - 1);
is_searching_with_regex = Some(
proc_widget_state
.process_search_state
.is_searching_with_regex,
);
}
}
// Also toggle it in the config file if we actually changed it.
if let Some(is_searching_whole_word) = is_searching_with_regex {
if let Some(flags) = &mut self.config.flags {
if let Some(map) = &mut flags.search_regex_enabled_widgets_map {
// Just update the map.
let mapping = map.entry(self.current_widget.widget_id - 1).or_default();
*mapping = is_searching_whole_word;
flags.search_regex_enabled_widgets =
Some(WidgetIdEnabled::create_from_hashmap(&map));
} else {
// Map doesn't exist yet... initialize ourselves.
let mut map = HashMap::default();
map.insert(self.current_widget.widget_id - 1, is_searching_whole_word);
flags.search_regex_enabled_widgets =
Some(WidgetIdEnabled::create_from_hashmap(&map));
flags.search_regex_enabled_widgets_map = Some(map);
}
} else {
// Must initialize it ourselves...
let mut map = HashMap::default();
map.insert(self.current_widget.widget_id - 1, is_searching_whole_word);
self.config.flags = Some(
ConfigFlags::builder()
.search_regex_enabled_widgets(WidgetIdEnabled::create_from_hashmap(&map))
.search_regex_enabled_widgets_map(map)
.build(),
);
}
// self.did_config_fail_to_save = self.update_config_file().is_err();
}
}
pub fn toggle_tree_mode(&mut self) {
@ -910,8 +760,7 @@ impl App {
}
pub fn on_up_key(&mut self) {
if self.is_config_open {
} else if !self.is_in_dialog() {
if !self.is_in_dialog() {
self.decrement_position_count();
} else if self.help_dialog_state.is_showing_help {
self.help_scroll_up();
@ -932,8 +781,7 @@ impl App {
}
pub fn on_down_key(&mut self) {
if self.is_config_open {
} else if !self.is_in_dialog() {
if !self.is_in_dialog() {
self.increment_position_count();
} else if self.help_dialog_state.is_showing_help {
self.help_scroll_down();
@ -954,8 +802,7 @@ impl App {
}
pub fn on_left_key(&mut self) {
if self.is_config_open {
} else if !self.is_in_dialog() {
if !self.is_in_dialog() {
match self.current_widget.widget_type {
BottomWidgetType::ProcSearch => {
let is_in_search_widget = self.is_in_search_widget();
@ -1026,8 +873,7 @@ impl App {
}
pub fn on_right_key(&mut self) {
if self.is_config_open {
} else if !self.is_in_dialog() {
if !self.is_in_dialog() {
match self.current_widget.widget_type {
BottomWidgetType::ProcSearch => {
let is_in_search_widget = self.is_in_search_widget();
@ -1163,7 +1009,6 @@ impl App {
}
}
}
} else if self.is_config_open {
}
}
@ -1210,7 +1055,6 @@ impl App {
}
}
}
} else if self.is_config_open {
}
}
@ -1464,7 +1308,6 @@ impl App {
'G' => self.skip_to_last(),
_ => {}
}
} else if self.is_config_open {
}
}
@ -1647,39 +1490,6 @@ impl App {
pub fn on_space(&mut self) {}
pub fn open_config_screen(&mut self) {
self.is_config_open = true;
self.is_force_redraw = true;
}
pub fn close_config_screen(&mut self) {
self.is_config_open = false;
self.is_force_redraw = true;
}
/// TODO: Disabled.
/// Call this whenever the config value is updated!
// fn update_config_file(&mut self) -> anyhow::Result<()> {
// if self.app_config_fields.no_write {
// // debug!("No write enabled. Config will not be written.");
// // Don't write!
// // FIXME: [CONFIG] This should be made VERY clear to the user... make a thing saying "it will not write due to no_write option"
// Ok(())
// } else if let Some(config_path) = &self.config_path {
// // Update
// // debug!("Updating config file - writing to: {:?}", config_path);
// std::fs::File::create(config_path)?
// .write_all(self.config.get_config_as_bytes()?.as_ref())?;
// Ok(())
// } else {
// // FIXME: [CONFIG] Put an actual error message?
// Err(anyhow::anyhow!(
// "Config path was missing, please try restarting bottom..."
// ))
// }
// Ok(())
// }
pub fn kill_highlighted_process(&mut self) -> Result<()> {
if let BottomWidgetType::Proc = self.current_widget.widget_type {
if let Some(current_selected_processes) = &self.to_delete_process_list {
@ -1763,7 +1573,7 @@ impl App {
WidgetDirection::Up => self.current_widget.up_neighbour,
WidgetDirection::Down => self.current_widget.down_neighbour,
}) {
if let Some(new_widget) = self.widget_map.get(&new_widget_id) {
if let Some(new_widget) = self.widget_map.get(new_widget_id) {
match &new_widget.widget_type {
BottomWidgetType::Temp
| BottomWidgetType::Proc
@ -2238,7 +2048,6 @@ impl App {
_ => {}
}
self.reset_multi_tap_keys();
} else if self.is_config_open {
} else if self.help_dialog_state.is_showing_help {
self.help_dialog_state.scroll_state.current_scroll_index = 0;
} else if self.delete_dialog_state.is_showing_dd {
@ -2317,7 +2126,6 @@ impl App {
_ => {}
}
self.reset_multi_tap_keys();
} else if self.is_config_open {
} else if self.help_dialog_state.is_showing_help {
self.help_dialog_state.scroll_state.current_scroll_index = self
.help_dialog_state
@ -2909,7 +2717,7 @@ impl App {
(widget.top_left_corner, widget.bottom_right_corner)
{
if (x >= tlc_x && y >= tlc_y) && (x < brc_x && y < brc_y) {
if let Some(new_widget) = self.widget_map.get(&new_widget_id) {
if let Some(new_widget) = self.widget_map.get(new_widget_id) {
self.current_widget = new_widget.clone();
match &self.current_widget.widget_type {

View File

@ -102,7 +102,7 @@ pub async fn get_cpu_data_list(
.enumerate()
.map(|(itx, (current_cpu, (past_cpu_work, past_cpu_total)))| {
if let Ok(cpu_time) = current_cpu {
let present_times = convert_cpu_times(&cpu_time);
let present_times = convert_cpu_times(cpu_time);
(
present_times,

View File

@ -238,7 +238,7 @@ impl DataCollector {
if let Some(battery_manager) = &self.battery_manager {
if let Some(battery_list) = &mut self.battery_list {
self.data.list_of_batteries =
Some(batteries::refresh_batteries(&battery_manager, battery_list));
Some(batteries::refresh_batteries(battery_manager, battery_list));
}
}

View File

@ -25,7 +25,7 @@ pub async fn get_network_data(
if filter.is_list_ignored {
let mut ret = true;
for r in &filter.list {
if r.is_match(&io.interface()) {
if r.is_match(io.interface()) {
ret = false;
break;
}

View File

@ -137,7 +137,7 @@ fn read_proc(
first_part
.rsplit_once('/')
.map(|(_prefix, suffix)| suffix)
.unwrap_or(&truncated_name)
.unwrap_or(truncated_name)
.to_string()
} else {
truncated_name.to_string()
@ -155,7 +155,7 @@ fn read_proc(
let process_state_char = stat.state;
let process_state = ProcessStatus::from(process_state_char).to_string();
let (cpu_usage_percent, new_process_times) = get_linux_cpu_usage(
&stat,
stat,
cpu_usage,
cpu_fraction,
prev_proc.cpu_time,
@ -258,7 +258,7 @@ pub fn get_process_data(
}
if let Ok((process_harvest, new_process_times)) = read_proc(
&prev_proc_details,
prev_proc_details,
stat,
cpu_usage,
cpu_fraction,

14
src/app/filter.rs Normal file
View File

@ -0,0 +1,14 @@
#[derive(Debug, Clone)]
pub struct Filter {
pub is_list_ignored: bool,
pub list: Vec<regex::Regex>,
}
/// For filtering out information
#[derive(Debug, Clone)]
pub struct DataFilters {
pub disk_filter: Option<Filter>,
pub mount_filter: Option<Filter>,
pub temp_filter: Option<Filter>,
pub net_filter: Option<Filter>,
}

View File

@ -0,0 +1,25 @@
use std::collections::HashMap;
#[derive(Default)]
pub struct BatteryWidgetState {
pub currently_selected_battery_index: usize,
pub tab_click_locs: Option<Vec<((u16, u16), (u16, u16))>>,
}
pub struct BatteryState {
pub widget_states: HashMap<u64, BatteryWidgetState>,
}
impl BatteryState {
pub fn init(widget_states: HashMap<u64, BatteryWidgetState>) -> Self {
BatteryState { widget_states }
}
pub fn get_mut_widget_state(&mut self, widget_id: u64) -> Option<&mut BatteryWidgetState> {
self.widget_states.get_mut(&widget_id)
}
pub fn get_widget_state(&self, widget_id: u64) -> Option<&BatteryWidgetState> {
self.widget_states.get(&widget_id)
}
}

View File

@ -0,0 +1,47 @@
use std::{collections::HashMap, time::Instant};
use super::{AppScrollWidgetState, CanvasTableWidthState};
pub struct CpuWidgetState {
pub current_display_time: u64,
pub is_legend_hidden: bool,
pub autohide_timer: Option<Instant>,
pub scroll_state: AppScrollWidgetState,
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 {
CpuWidgetState {
current_display_time,
is_legend_hidden: false,
autohide_timer,
scroll_state: AppScrollWidgetState::default(),
is_multi_graph_mode: false,
table_width_state: CanvasTableWidthState::default(),
}
}
}
pub struct CpuState {
pub force_update: Option<u64>,
pub widget_states: HashMap<u64, CpuWidgetState>,
}
impl CpuState {
pub fn init(widget_states: HashMap<u64, CpuWidgetState>) -> Self {
CpuState {
force_update: None,
widget_states,
}
}
pub fn get_mut_widget_state(&mut self, widget_id: u64) -> Option<&mut CpuWidgetState> {
self.widget_states.get_mut(&widget_id)
}
pub fn get_widget_state(&self, widget_id: u64) -> Option<&CpuWidgetState> {
self.widget_states.get(&widget_id)
}
}

View File

@ -0,0 +1,35 @@
use std::collections::HashMap;
use super::{AppScrollWidgetState, CanvasTableWidthState};
pub struct DiskWidgetState {
pub scroll_state: AppScrollWidgetState,
pub table_width_state: CanvasTableWidthState,
}
impl DiskWidgetState {
pub fn init() -> Self {
DiskWidgetState {
scroll_state: AppScrollWidgetState::default(),
table_width_state: CanvasTableWidthState::default(),
}
}
}
pub struct DiskState {
pub widget_states: HashMap<u64, DiskWidgetState>,
}
impl DiskState {
pub fn init(widget_states: HashMap<u64, DiskWidgetState>) -> Self {
DiskState { widget_states }
}
pub fn get_mut_widget_state(&mut self, widget_id: u64) -> Option<&mut DiskWidgetState> {
self.widget_states.get_mut(&widget_id)
}
pub fn get_widget_state(&self, widget_id: u64) -> Option<&DiskWidgetState> {
self.widget_states.get(&widget_id)
}
}

View File

@ -0,0 +1 @@
//! States for a graph widget.

View File

@ -0,0 +1,37 @@
use std::{collections::HashMap, time::Instant};
pub struct MemWidgetState {
pub current_display_time: u64,
pub autohide_timer: Option<Instant>,
}
impl MemWidgetState {
pub fn init(current_display_time: u64, autohide_timer: Option<Instant>) -> Self {
MemWidgetState {
current_display_time,
autohide_timer,
}
}
}
pub struct MemState {
pub force_update: Option<u64>,
pub widget_states: HashMap<u64, MemWidgetState>,
}
impl MemState {
pub fn init(widget_states: HashMap<u64, MemWidgetState>) -> Self {
MemState {
force_update: None,
widget_states,
}
}
pub fn get_mut_widget_state(&mut self, widget_id: u64) -> Option<&mut MemWidgetState> {
self.widget_states.get_mut(&widget_id)
}
pub fn get_widget_state(&self, widget_id: u64) -> Option<&MemWidgetState> {
self.widget_states.get(&widget_id)
}
}

View File

@ -0,0 +1,125 @@
use std::time::Instant;
use tui::widgets::TableState;
use crate::{app::layout_manager::BottomWidgetType, constants};
pub mod process_state;
pub use process_state::*;
pub mod net_state;
pub use net_state::*;
pub mod mem_state;
pub use mem_state::*;
pub mod cpu_state;
pub use cpu_state::*;
pub mod disk_state;
pub use disk_state::*;
pub mod battery_state;
pub use battery_state::*;
pub mod temp_state;
pub use temp_state::*;
#[derive(Debug)]
pub enum ScrollDirection {
// UP means scrolling up --- this usually DECREMENTS
Up,
// DOWN means scrolling down --- this usually INCREMENTS
Down,
}
impl Default for ScrollDirection {
fn default() -> Self {
ScrollDirection::Down
}
}
#[derive(Debug)]
pub enum CursorDirection {
Left,
Right,
}
/// AppScrollWidgetState deals with fields for a scrollable app's current state.
#[derive(Default)]
pub struct AppScrollWidgetState {
pub current_scroll_position: usize,
pub previous_scroll_position: usize,
pub scroll_direction: ScrollDirection,
pub table_state: TableState,
}
#[derive(PartialEq)]
pub enum KillSignal {
Cancel,
Kill(usize),
}
impl Default for KillSignal {
#[cfg(target_family = "unix")]
fn default() -> Self {
KillSignal::Kill(15)
}
#[cfg(target_os = "windows")]
fn default() -> Self {
KillSignal::Kill(1)
}
}
#[derive(Default)]
pub struct AppDeleteDialogState {
pub is_showing_dd: bool,
pub selected_signal: KillSignal,
/// tl x, tl y, br x, br y, index/signal
pub button_positions: Vec<(u16, u16, u16, u16, usize)>,
pub keyboard_signal_select: usize,
pub last_number_press: Option<Instant>,
pub scroll_pos: usize,
}
pub struct AppHelpDialogState {
pub is_showing_help: bool,
pub scroll_state: ParagraphScrollState,
pub index_shortcuts: Vec<u16>,
}
impl Default for AppHelpDialogState {
fn default() -> Self {
AppHelpDialogState {
is_showing_help: false,
scroll_state: ParagraphScrollState::default(),
index_shortcuts: vec![0; constants::HELP_TEXT.len()],
}
}
}
/// Meant for canvas operations involving table column widths.
#[derive(Default)]
pub struct CanvasTableWidthState {
pub desired_column_widths: Vec<u16>,
pub calculated_column_widths: Vec<u16>,
}
pub struct BasicTableWidgetState {
// Since this is intended (currently) to only be used for ONE widget, that's
// how it's going to be written. If we want to allow for multiple of these,
// then we can expand outwards with a normal BasicTableState and a hashmap
pub currently_displayed_widget_type: BottomWidgetType,
pub currently_displayed_widget_id: u64,
pub widget_id: i64,
pub left_tlc: Option<(u16, u16)>,
pub left_brc: Option<(u16, u16)>,
pub right_tlc: Option<(u16, u16)>,
pub right_brc: Option<(u16, u16)>,
}
#[derive(Default)]
pub struct ParagraphScrollState {
pub current_scroll_index: u16,
pub max_scroll_index: u16,
}

View File

@ -0,0 +1,52 @@
use std::{collections::HashMap, time::Instant};
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 {
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,
}
}
}
pub struct NetState {
pub force_update: Option<u64>,
pub widget_states: HashMap<u64, NetWidgetState>,
}
impl NetState {
pub fn init(widget_states: HashMap<u64, NetWidgetState>) -> Self {
NetState {
force_update: None,
widget_states,
}
}
pub fn get_mut_widget_state(&mut self, widget_id: u64) -> Option<&mut NetWidgetState> {
self.widget_states.get_mut(&widget_id)
}
pub fn get_widget_state(&self, widget_id: u64) -> Option<&NetWidgetState> {
self.widget_states.get(&widget_id)
}
}

View File

@ -1,88 +1,16 @@
use std::{collections::HashMap, time::Instant};
use std::collections::HashMap;
use unicode_segmentation::GraphemeCursor;
use tui::widgets::TableState;
use crate::{
app::{layout_manager::BottomWidgetType, query::*},
constants,
app::query::*,
data_harvester::processes::{self, ProcessSorting},
};
use ProcessSorting::*;
#[derive(Debug)]
pub enum ScrollDirection {
// UP means scrolling up --- this usually DECREMENTS
Up,
// DOWN means scrolling down --- this usually INCREMENTS
Down,
}
impl Default for ScrollDirection {
fn default() -> Self {
ScrollDirection::Down
}
}
#[derive(Debug)]
pub enum CursorDirection {
Left,
Right,
}
/// AppScrollWidgetState deals with fields for a scrollable app's current state.
#[derive(Default)]
pub struct AppScrollWidgetState {
pub current_scroll_position: usize,
pub previous_scroll_position: usize,
pub scroll_direction: ScrollDirection,
pub table_state: TableState,
}
#[derive(PartialEq)]
pub enum KillSignal {
Cancel,
Kill(usize),
}
impl Default for KillSignal {
#[cfg(target_family = "unix")]
fn default() -> Self {
KillSignal::Kill(15)
}
#[cfg(target_os = "windows")]
fn default() -> Self {
KillSignal::Kill(1)
}
}
#[derive(Default)]
pub struct AppDeleteDialogState {
pub is_showing_dd: bool,
pub selected_signal: KillSignal,
/// tl x, tl y, br x, br y, index/signal
pub button_positions: Vec<(u16, u16, u16, u16, usize)>,
pub keyboard_signal_select: usize,
pub last_number_press: Option<Instant>,
pub scroll_pos: usize,
}
pub struct AppHelpDialogState {
pub is_showing_help: bool,
pub scroll_state: ParagraphScrollState,
pub index_shortcuts: Vec<u16>,
}
impl Default for AppHelpDialogState {
fn default() -> Self {
AppHelpDialogState {
is_showing_help: false,
scroll_state: ParagraphScrollState::default(),
index_shortcuts: vec![0; constants::HELP_TEXT.len()],
}
}
}
use super::{AppScrollWidgetState, CanvasTableWidthState, CursorDirection, ScrollDirection};
/// AppSearchState deals with generic searching (I might do this in the future).
pub struct AppSearchState {
@ -131,13 +59,6 @@ impl AppSearchState {
}
}
/// Meant for canvas operations involving table column widths.
#[derive(Default)]
pub struct CanvasTableWidthState {
pub desired_column_widths: Vec<u16>,
pub calculated_column_widths: Vec<u16>,
}
/// ProcessSearchState only deals with process' search's current settings and state.
pub struct ProcessSearchState {
pub search_state: AppSearchState,
@ -383,7 +304,7 @@ impl ProcColumn {
self.ordered_columns
.iter()
.filter_map(|column_type| {
if let Some(col_map) = self.column_mapping.get(&column_type) {
if let Some(col_map) = self.column_mapping.get(column_type) {
if col_map.enabled {
Some(1)
} else {
@ -429,7 +350,7 @@ impl ProcColumn {
self.ordered_columns
.iter()
.filter_map(|column_type| {
let mapping = self.column_mapping.get(&column_type).unwrap();
let mapping = self.column_mapping.get(column_type).unwrap();
let mut command_str = String::default();
if let Some(command) = mapping.shortcut {
command_str = format!("({})", command);
@ -685,256 +606,3 @@ impl ProcState {
self.widget_states.get(&widget_id)
}
}
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 {
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,
}
}
}
pub struct NetState {
pub force_update: Option<u64>,
pub widget_states: HashMap<u64, NetWidgetState>,
}
impl NetState {
pub fn init(widget_states: HashMap<u64, NetWidgetState>) -> Self {
NetState {
force_update: None,
widget_states,
}
}
pub fn get_mut_widget_state(&mut self, widget_id: u64) -> Option<&mut NetWidgetState> {
self.widget_states.get_mut(&widget_id)
}
pub fn get_widget_state(&self, widget_id: u64) -> Option<&NetWidgetState> {
self.widget_states.get(&widget_id)
}
}
pub struct CpuWidgetState {
pub current_display_time: u64,
pub is_legend_hidden: bool,
pub autohide_timer: Option<Instant>,
pub scroll_state: AppScrollWidgetState,
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 {
CpuWidgetState {
current_display_time,
is_legend_hidden: false,
autohide_timer,
scroll_state: AppScrollWidgetState::default(),
is_multi_graph_mode: false,
table_width_state: CanvasTableWidthState::default(),
}
}
}
pub struct CpuState {
pub force_update: Option<u64>,
pub widget_states: HashMap<u64, CpuWidgetState>,
}
impl CpuState {
pub fn init(widget_states: HashMap<u64, CpuWidgetState>) -> Self {
CpuState {
force_update: None,
widget_states,
}
}
pub fn get_mut_widget_state(&mut self, widget_id: u64) -> Option<&mut CpuWidgetState> {
self.widget_states.get_mut(&widget_id)
}
pub fn get_widget_state(&self, widget_id: u64) -> Option<&CpuWidgetState> {
self.widget_states.get(&widget_id)
}
}
pub struct MemWidgetState {
pub current_display_time: u64,
pub autohide_timer: Option<Instant>,
}
impl MemWidgetState {
pub fn init(current_display_time: u64, autohide_timer: Option<Instant>) -> Self {
MemWidgetState {
current_display_time,
autohide_timer,
}
}
}
pub struct MemState {
pub force_update: Option<u64>,
pub widget_states: HashMap<u64, MemWidgetState>,
}
impl MemState {
pub fn init(widget_states: HashMap<u64, MemWidgetState>) -> Self {
MemState {
force_update: None,
widget_states,
}
}
pub fn get_mut_widget_state(&mut self, widget_id: u64) -> Option<&mut MemWidgetState> {
self.widget_states.get_mut(&widget_id)
}
pub fn get_widget_state(&self, widget_id: u64) -> Option<&MemWidgetState> {
self.widget_states.get(&widget_id)
}
}
pub struct TempWidgetState {
pub scroll_state: AppScrollWidgetState,
pub table_width_state: CanvasTableWidthState,
}
impl TempWidgetState {
pub fn init() -> Self {
TempWidgetState {
scroll_state: AppScrollWidgetState::default(),
table_width_state: CanvasTableWidthState::default(),
}
}
}
pub struct TempState {
pub widget_states: HashMap<u64, TempWidgetState>,
}
impl TempState {
pub fn init(widget_states: HashMap<u64, TempWidgetState>) -> Self {
TempState { widget_states }
}
pub fn get_mut_widget_state(&mut self, widget_id: u64) -> Option<&mut TempWidgetState> {
self.widget_states.get_mut(&widget_id)
}
pub fn get_widget_state(&self, widget_id: u64) -> Option<&TempWidgetState> {
self.widget_states.get(&widget_id)
}
}
pub struct DiskWidgetState {
pub scroll_state: AppScrollWidgetState,
pub table_width_state: CanvasTableWidthState,
}
impl DiskWidgetState {
pub fn init() -> Self {
DiskWidgetState {
scroll_state: AppScrollWidgetState::default(),
table_width_state: CanvasTableWidthState::default(),
}
}
}
pub struct DiskState {
pub widget_states: HashMap<u64, DiskWidgetState>,
}
impl DiskState {
pub fn init(widget_states: HashMap<u64, DiskWidgetState>) -> Self {
DiskState { widget_states }
}
pub fn get_mut_widget_state(&mut self, widget_id: u64) -> Option<&mut DiskWidgetState> {
self.widget_states.get_mut(&widget_id)
}
pub fn get_widget_state(&self, widget_id: u64) -> Option<&DiskWidgetState> {
self.widget_states.get(&widget_id)
}
}
pub struct BasicTableWidgetState {
// Since this is intended (currently) to only be used for ONE widget, that's
// how it's going to be written. If we want to allow for multiple of these,
// then we can expand outwards with a normal BasicTableState and a hashmap
pub currently_displayed_widget_type: BottomWidgetType,
pub currently_displayed_widget_id: u64,
pub widget_id: i64,
pub left_tlc: Option<(u16, u16)>,
pub left_brc: Option<(u16, u16)>,
pub right_tlc: Option<(u16, u16)>,
pub right_brc: Option<(u16, u16)>,
}
#[derive(Default)]
pub struct BatteryWidgetState {
pub currently_selected_battery_index: usize,
pub tab_click_locs: Option<Vec<((u16, u16), (u16, u16))>>,
}
pub struct BatteryState {
pub widget_states: HashMap<u64, BatteryWidgetState>,
}
impl BatteryState {
pub fn init(widget_states: HashMap<u64, BatteryWidgetState>) -> Self {
BatteryState { widget_states }
}
pub fn get_mut_widget_state(&mut self, widget_id: u64) -> Option<&mut BatteryWidgetState> {
self.widget_states.get_mut(&widget_id)
}
pub fn get_widget_state(&self, widget_id: u64) -> Option<&BatteryWidgetState> {
self.widget_states.get(&widget_id)
}
}
#[derive(Default)]
pub struct ParagraphScrollState {
pub current_scroll_index: u16,
pub max_scroll_index: u16,
}
#[derive(Default)]
pub struct ConfigState {
pub current_category_index: usize,
pub category_list: Vec<ConfigCategory>,
}
#[derive(Default)]
pub struct ConfigCategory {
pub category_name: &'static str,
pub options_list: Vec<ConfigOption>,
}
pub struct ConfigOption {
pub set_function: Box<dyn Fn() -> anyhow::Result<()>>,
}

View File

@ -0,0 +1 @@
//! States for a table widget.

View File

@ -0,0 +1,35 @@
use std::collections::HashMap;
use super::{AppScrollWidgetState, CanvasTableWidthState};
pub struct TempWidgetState {
pub scroll_state: AppScrollWidgetState,
pub table_width_state: CanvasTableWidthState,
}
impl TempWidgetState {
pub fn init() -> Self {
TempWidgetState {
scroll_state: AppScrollWidgetState::default(),
table_width_state: CanvasTableWidthState::default(),
}
}
}
pub struct TempState {
pub widget_states: HashMap<u64, TempWidgetState>,
}
impl TempState {
pub fn init(widget_states: HashMap<u64, TempWidgetState>) -> Self {
TempState { widget_states }
}
pub fn get_mut_widget_state(&mut self, widget_id: u64) -> Option<&mut TempWidgetState> {
self.widget_states.get_mut(&widget_id)
}
pub fn get_widget_state(&self, widget_id: u64) -> Option<&TempWidgetState> {
self.widget_states.get(&widget_id)
}
}

View File

@ -50,7 +50,6 @@ fn main() -> Result<()> {
&widget_layout,
default_widget_id,
&default_widget_type_option,
config_path,
)?;
// Create painter and set colours.

View File

@ -13,14 +13,13 @@ use tui::{
use canvas_colours::*;
use dialogs::*;
use screens::*;
use widgets::*;
use crate::{
app::{
self,
layout_manager::{BottomColRow, BottomLayout, BottomWidgetType},
App,
AppState,
},
constants::*,
data_conversion::{ConvertedBatteryData, ConvertedCpuData, ConvertedProcessData},
@ -33,7 +32,6 @@ use crate::{
mod canvas_colours;
mod dialogs;
mod drawing_utils;
mod screens;
mod widgets;
/// Point is of time, data
@ -299,7 +297,7 @@ impl Painter {
}
pub fn draw_data<B: Backend>(
&mut self, terminal: &mut Terminal<B>, app_state: &mut app::App,
&mut self, terminal: &mut Terminal<B>, app_state: &mut app::AppState,
) -> error::Result<()> {
use BottomWidgetType::*;
@ -521,13 +519,6 @@ impl Painter {
),
_ => {}
}
} else if app_state.is_config_open {
let rect = Layout::default()
.margin(0)
.constraints([Constraint::Percentage(100)])
.split(f.size())[0];
self.draw_config_screen(&mut f, app_state, rect)
} else if app_state.app_config_fields.use_basic_mode {
// Basic mode. This basically removes all graphs but otherwise
// the same info.
@ -701,7 +692,7 @@ impl Painter {
&mut f,
app_state,
widgets,
&widget_draw_locs,
widget_draw_locs,
);
});
}
@ -715,7 +706,7 @@ impl Painter {
}
fn draw_widgets_with_constraints<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, widgets: &BottomColRow,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, widgets: &BottomColRow,
widget_draw_locs: &[Rect],
) {
use BottomWidgetType::*;

View File

@ -9,7 +9,7 @@ use tui::{
};
use crate::{
app::{App, KillSignal},
app::{AppState, KillSignal},
canvas::Painter,
};
@ -17,19 +17,20 @@ const DD_BASE: &str = " Confirm Kill Process ── Esc to close ";
const DD_ERROR_BASE: &str = " Error ── Esc to close ";
pub trait KillDialog {
fn get_dd_spans(&self, app_state: &App) -> Option<Text<'_>>;
fn get_dd_spans(&self, app_state: &AppState) -> Option<Text<'_>>;
fn draw_dd_confirm_buttons<B: Backend>(
&self, f: &mut Frame<'_, B>, button_draw_loc: &Rect, app_state: &mut App,
&self, f: &mut Frame<'_, B>, button_draw_loc: &Rect, app_state: &mut AppState,
);
fn draw_dd_dialog<B: Backend>(
&self, f: &mut Frame<'_, B>, dd_text: Option<Text<'_>>, app_state: &mut App, draw_loc: Rect,
&self, f: &mut Frame<'_, B>, dd_text: Option<Text<'_>>, app_state: &mut AppState,
draw_loc: Rect,
) -> bool;
}
impl KillDialog for Painter {
fn get_dd_spans(&self, app_state: &App) -> Option<Text<'_>> {
fn get_dd_spans(&self, app_state: &AppState) -> Option<Text<'_>> {
if let Some(dd_err) = &app_state.dd_err {
return Some(Text::from(vec![
Spans::default(),
@ -68,7 +69,7 @@ impl KillDialog for Painter {
}
fn draw_dd_confirm_buttons<B: Backend>(
&self, f: &mut Frame<'_, B>, button_draw_loc: &Rect, app_state: &mut App,
&self, f: &mut Frame<'_, B>, button_draw_loc: &Rect, app_state: &mut AppState,
) {
if cfg!(target_os = "windows") || !app_state.app_config_fields.is_advanced_kill {
let (yes_button, no_button) = match app_state.delete_dialog_state.selected_signal {
@ -318,7 +319,8 @@ impl KillDialog for Painter {
}
fn draw_dd_dialog<B: Backend>(
&self, f: &mut Frame<'_, B>, dd_text: Option<Text<'_>>, app_state: &mut App, draw_loc: Rect,
&self, f: &mut Frame<'_, B>, dd_text: Option<Text<'_>>, app_state: &mut AppState,
draw_loc: Rect,
) -> bool {
if let Some(dd_text) = dd_text {
let dd_title = if app_state.dd_err.is_some() {

View File

@ -1,6 +1,6 @@
use unicode_width::UnicodeWidthStr;
use crate::{app::App, canvas::Painter, constants};
use crate::{app::AppState, canvas::Painter, constants};
use tui::{
backend::Backend,
layout::{Alignment, Rect},
@ -14,14 +14,14 @@ const HELP_BASE: &str = " Help ── Esc to close ";
pub trait HelpDialog {
fn draw_help_dialog<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect,
);
}
// TODO: [REFACTOR] Make generic dialog boxes to build off of instead?
impl HelpDialog for Painter {
fn draw_help_dialog<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect,
) {
let help_title = Spans::from(vec![
Span::styled(" Help ", self.colours.widget_title_style),

View File

@ -1,3 +0,0 @@
pub mod config_screen;
pub use config_screen::*;

View File

@ -1,33 +0,0 @@
#![allow(unused_variables)] //FIXME: Remove this
#![allow(unused_imports)] //FIXME: Remove this
use crate::{app::App, canvas::Painter, constants};
use tui::{
backend::Backend,
layout::Constraint,
layout::Direction,
layout::Layout,
layout::{Alignment, Rect},
terminal::Frame,
text::Span,
widgets::{Block, Borders, Paragraph},
};
pub trait ConfigScreen {
fn draw_config_screen<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect,
);
}
impl ConfigScreen for Painter {
fn draw_config_screen<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect,
) {
let config_block = Block::default()
.title(Span::styled(" Config ", self.colours.widget_title_style))
.style(self.colours.border_style)
.borders(Borders::ALL)
.border_style(self.colours.border_style);
f.render_widget(config_block, draw_loc);
}
}

View File

@ -1,5 +1,5 @@
use crate::{
app::{layout_manager::BottomWidgetType, App},
app::{layout_manager::BottomWidgetType, AppState},
canvas::Painter,
};
@ -14,13 +14,13 @@ use tui::{
pub trait BasicTableArrows {
fn draw_basic_table_arrows<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, widget_id: u64,
);
}
impl BasicTableArrows for Painter {
fn draw_basic_table_arrows<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, widget_id: u64,
) {
if let Some(current_table) = app_state.widget_map.get(&widget_id) {
let current_table = if let BottomWidgetType::ProcSort = current_table.widget_type {

View File

@ -1,5 +1,5 @@
use crate::{
app::App,
app::AppState,
canvas::{drawing_utils::calculate_basic_use_bars, Painter},
constants::*,
};
@ -15,14 +15,14 @@ use unicode_segmentation::UnicodeSegmentation;
pub trait BatteryDisplayWidget {
fn draw_battery_display<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, draw_border: bool,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, draw_border: bool,
widget_id: u64,
);
}
impl BatteryDisplayWidget for Painter {
fn draw_battery_display<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, draw_border: bool,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, draw_border: bool,
widget_id: u64,
) {
let should_get_widget_bounds = app_state.should_get_widget_bounds();

View File

@ -1,7 +1,7 @@
use std::cmp::min;
use crate::{
app::App,
app::AppState,
canvas::{drawing_utils::*, Painter},
constants::*,
data_conversion::ConvertedCpuData,
@ -17,13 +17,13 @@ use tui::{
pub trait CpuBasicWidget {
fn draw_basic_cpu<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, widget_id: u64,
);
}
impl CpuBasicWidget for Painter {
fn draw_basic_cpu<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, widget_id: u64,
) {
// Skip the first element, it's the "all" element
if app_state.canvas_data.cpu_data.len() > 1 {

View File

@ -2,7 +2,7 @@ use once_cell::sync::Lazy;
use unicode_segmentation::UnicodeSegmentation;
use crate::{
app::{layout_manager::WidgetDirection, App},
app::{layout_manager::WidgetDirection, AppState},
canvas::{
drawing_utils::{get_column_widths, get_start_position, interpolate_points},
Painter,
@ -34,19 +34,19 @@ static CPU_LEGEND_HEADER_LENS: Lazy<Vec<u16>> = Lazy::new(|| {
pub trait CpuGraphWidget {
fn draw_cpu<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, widget_id: u64,
);
fn draw_cpu_graph<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, widget_id: u64,
);
fn draw_cpu_legend<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, widget_id: u64,
);
}
impl CpuGraphWidget for Painter {
fn draw_cpu<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, widget_id: u64,
) {
if draw_loc.width as f64 * 0.15 <= 6.0 {
// Skip drawing legend
@ -132,7 +132,7 @@ impl CpuGraphWidget for Painter {
}
fn draw_cpu_graph<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, widget_id: u64,
) {
if let Some(cpu_widget_state) = app_state.cpu_state.widget_states.get_mut(&widget_id) {
let cpu_data: &mut [ConvertedCpuData] = &mut app_state.canvas_data.cpu_data;
@ -382,7 +382,7 @@ impl CpuGraphWidget for Painter {
}
fn draw_cpu_legend<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, widget_id: u64,
) {
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))

View File

@ -29,15 +29,15 @@ static DISK_HEADERS_LENS: Lazy<Vec<u16>> = Lazy::new(|| {
pub trait DiskTableWidget {
fn draw_disk_table<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut app::App, draw_loc: Rect, draw_border: bool,
widget_id: u64,
&self, f: &mut Frame<'_, B>, app_state: &mut app::AppState, draw_loc: Rect,
draw_border: bool, widget_id: u64,
);
}
impl DiskTableWidget for Painter {
fn draw_disk_table<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut app::App, draw_loc: Rect, draw_border: bool,
widget_id: u64,
&self, f: &mut Frame<'_, B>, app_state: &mut app::AppState, draw_loc: Rect,
draw_border: bool, widget_id: u64,
) {
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) {

View File

@ -1,5 +1,5 @@
use crate::{
app::App,
app::AppState,
canvas::{drawing_utils::*, Painter},
constants::*,
};
@ -15,13 +15,13 @@ use tui::{
pub trait MemBasicWidget {
fn draw_basic_memory<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, widget_id: u64,
);
}
impl MemBasicWidget for Painter {
fn draw_basic_memory<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, widget_id: u64,
) {
let mem_data: &[(f64, f64)] = &app_state.canvas_data.mem_data;
let swap_data: &[(f64, f64)] = &app_state.canvas_data.swap_data;

View File

@ -1,5 +1,5 @@
use crate::{
app::App,
app::AppState,
canvas::{drawing_utils::interpolate_points, Painter},
constants::*,
};
@ -17,13 +17,13 @@ use unicode_segmentation::UnicodeSegmentation;
pub trait MemGraphWidget {
fn draw_memory_graph<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, widget_id: u64,
);
}
impl MemGraphWidget for Painter {
fn draw_memory_graph<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, widget_id: u64,
) {
if let Some(mem_widget_state) = app_state.mem_state.widget_states.get_mut(&widget_id) {
let mem_data: &mut [(f64, f64)] = &mut app_state.canvas_data.mem_data;
@ -156,7 +156,7 @@ impl MemGraphWidget for Painter {
Marker::Braille
})
.style(self.colours.ram_style)
.data(&mem_data)
.data(mem_data)
.graph_type(tui::widgets::GraphType::Line),
);
}
@ -172,7 +172,7 @@ impl MemGraphWidget for Painter {
Marker::Braille
})
.style(self.colours.swap_style)
.data(&swap_data)
.data(swap_data)
.graph_type(tui::widgets::GraphType::Line),
);
}

View File

@ -1,4 +1,4 @@
use crate::{app::App, canvas::Painter, constants::*};
use crate::{app::AppState, canvas::Painter, constants::*};
use tui::{
backend::Backend,
@ -10,13 +10,13 @@ use tui::{
pub trait NetworkBasicWidget {
fn draw_basic_network<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, widget_id: u64,
);
}
impl NetworkBasicWidget for Painter {
fn draw_basic_network<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, widget_id: u64,
) {
let divided_loc = Layout::default()
.direction(Direction::Horizontal)

View File

@ -3,7 +3,7 @@ use std::cmp::max;
use unicode_segmentation::UnicodeSegmentation;
use crate::{
app::{App, AxisScaling},
app::{AppState, AxisScaling},
canvas::{
drawing_utils::{get_column_widths, interpolate_points},
Painter,
@ -34,22 +34,22 @@ static NETWORK_HEADERS_LENS: Lazy<Vec<u16>> = Lazy::new(|| {
pub trait NetworkGraphWidget {
fn draw_network<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, widget_id: u64,
);
fn draw_network_graph<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, widget_id: u64,
hide_legend: bool,
);
fn draw_network_labels<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, widget_id: u64,
);
}
impl NetworkGraphWidget for Painter {
fn draw_network<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, widget_id: u64,
) {
if app_state.app_config_fields.use_old_network_legend {
let network_chunk = Layout::default()
@ -80,7 +80,7 @@ impl NetworkGraphWidget for Painter {
}
fn draw_network_graph<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, widget_id: u64,
hide_legend: bool,
) {
/// Point is of time, data
@ -618,7 +618,7 @@ impl NetworkGraphWidget for Painter {
Marker::Braille
})
.style(self.colours.rx_style)
.data(&network_data_rx)
.data(network_data_rx)
.graph_type(tui::widgets::GraphType::Line),
Dataset::default()
.name(format!("TX: {:7}", app_state.canvas_data.tx_display))
@ -628,7 +628,7 @@ impl NetworkGraphWidget for Painter {
Marker::Braille
})
.style(self.colours.tx_style)
.data(&network_data_tx)
.data(network_data_tx)
.graph_type(tui::widgets::GraphType::Line),
Dataset::default()
.name(format!(
@ -653,7 +653,7 @@ impl NetworkGraphWidget for Painter {
Marker::Braille
})
.style(self.colours.rx_style)
.data(&network_data_rx)
.data(network_data_rx)
.graph_type(tui::widgets::GraphType::Line),
Dataset::default()
.name(&app_state.canvas_data.tx_display)
@ -663,7 +663,7 @@ impl NetworkGraphWidget for Painter {
Marker::Braille
})
.style(self.colours.tx_style)
.data(&network_data_tx)
.data(network_data_tx)
.graph_type(tui::widgets::GraphType::Line),
]
};
@ -702,7 +702,7 @@ impl NetworkGraphWidget for Painter {
}
fn draw_network_labels<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, widget_id: u64,
) {
let table_gap = if draw_loc.height < TABLE_GAP_HEIGHT_LIMIT {
0

View File

@ -1,5 +1,5 @@
use crate::{
app::App,
app::AppState,
canvas::{
drawing_utils::{get_column_widths, get_search_start_position, get_start_position},
Painter,
@ -103,7 +103,7 @@ pub trait ProcessTableWidget {
/// Draws and handles all process-related drawing. Use this.
/// - `widget_id` here represents the widget ID of the process widget itself!
fn draw_process_features<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, draw_border: bool,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, draw_border: bool,
widget_id: u64,
);
@ -112,7 +112,7 @@ pub trait ProcessTableWidget {
///
/// This should not be directly called.
fn draw_processes_table<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, draw_border: bool,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, draw_border: bool,
widget_id: u64,
);
@ -122,7 +122,7 @@ pub trait ProcessTableWidget {
///
/// This should not be directly called.
fn draw_search_field<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, draw_border: bool,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, draw_border: bool,
widget_id: u64,
);
@ -132,14 +132,14 @@ pub trait ProcessTableWidget {
///
/// This should not be directly called.
fn draw_process_sort<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, draw_border: bool,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, draw_border: bool,
widget_id: u64,
);
}
impl ProcessTableWidget for Painter {
fn draw_process_features<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, draw_border: bool,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, draw_border: bool,
widget_id: u64,
) {
if let Some(process_widget_state) = app_state.proc_state.widget_states.get(&widget_id) {
@ -185,7 +185,7 @@ impl ProcessTableWidget for Painter {
}
fn draw_processes_table<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, draw_border: bool,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, draw_border: bool,
widget_id: u64,
) {
let should_get_widget_bounds = app_state.should_get_widget_bounds();
@ -419,7 +419,7 @@ impl ProcessTableWidget for Painter {
proc_widget_state.table_width_state.calculated_column_widths =
get_column_widths(
draw_loc.width,
&hard_widths,
hard_widths,
&soft_widths_min,
soft_widths_max,
&(proc_widget_state
@ -567,7 +567,7 @@ impl ProcessTableWidget for Painter {
}
fn draw_search_field<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, draw_border: bool,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, draw_border: bool,
widget_id: u64,
) {
fn build_query<'a>(
@ -786,7 +786,7 @@ impl ProcessTableWidget for Painter {
}
fn draw_process_sort<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, draw_border: bool,
&self, f: &mut Frame<'_, B>, app_state: &mut AppState, draw_loc: Rect, draw_border: bool,
widget_id: u64,
) {
let is_on_widget = widget_id == app_state.current_widget.widget_id;
@ -803,7 +803,7 @@ impl ProcessTableWidget for Painter {
proc_widget_state
.columns
.column_mapping
.get(&column_type)
.get(column_type)
.unwrap()
.enabled
})

View File

@ -29,15 +29,15 @@ static TEMP_HEADERS_LENS: Lazy<Vec<u16>> = Lazy::new(|| {
pub trait TempTableWidget {
fn draw_temp_table<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut app::App, draw_loc: Rect, draw_border: bool,
widget_id: u64,
&self, f: &mut Frame<'_, B>, app_state: &mut app::AppState, draw_loc: Rect,
draw_border: bool, widget_id: u64,
);
}
impl TempTableWidget for Painter {
fn draw_temp_table<B: Backend>(
&self, f: &mut Frame<'_, B>, app_state: &mut app::App, draw_loc: Rect, draw_border: bool,
widget_id: u64,
&self, f: &mut Frame<'_, B>, app_state: &mut app::AppState, draw_loc: Rect,
draw_border: bool, widget_id: u64,
) {
let recalculate_column_widths = app_state.should_get_widget_bounds();
if let Some(temp_widget_state) = app_state.temp_state.widget_states.get_mut(&widget_id) {

View File

@ -2,7 +2,7 @@
//! can actually handle.
use crate::{app::AxisScaling, units::data_units::DataUnit, Pid};
use crate::{
app::{data_farmer, data_harvester, App, ProcWidgetState},
app::{data_farmer, data_harvester, AppState, ProcWidgetState},
utils::{self, gen_util::*},
};
use data_harvester::processes::ProcessSorting;
@ -83,7 +83,7 @@ pub struct ConvertedCpuData {
pub legend_value: String,
}
pub fn convert_temp_row(app: &App) -> Vec<Vec<String>> {
pub fn convert_temp_row(app: &AppState) -> Vec<Vec<String>> {
let current_data = &app.data_collection;
let temp_type = &app.app_config_fields.temperature_type;

View File

@ -29,7 +29,7 @@ use crossterm::{
use app::{
data_harvester::{self, processes::ProcessSorting},
layout_manager::{UsedWidgets, WidgetDirection},
App,
AppState,
};
use constants::*;
use data_conversion::*;
@ -71,7 +71,7 @@ pub enum ThreadControlEvent {
UpdateUpdateTime(u64),
}
pub fn handle_mouse_event(event: MouseEvent, app: &mut App) {
pub fn handle_mouse_event(event: MouseEvent, app: &mut AppState) {
match event {
MouseEvent::ScrollUp(_x, _y, _modifiers) => app.handle_scroll_up(),
MouseEvent::ScrollDown(_x, _y, _modifiers) => app.handle_scroll_down(),
@ -92,7 +92,7 @@ pub fn handle_mouse_event(event: MouseEvent, app: &mut App) {
}
pub fn handle_key_event_or_break(
event: KeyEvent, app: &mut App, reset_sender: &std::sync::mpsc::Sender<ThreadControlEvent>,
event: KeyEvent, app: &mut AppState, reset_sender: &std::sync::mpsc::Sender<ThreadControlEvent>,
) -> bool {
// debug!("KeyEvent: {:?}", event);
@ -240,7 +240,7 @@ pub fn create_or_get_config(config_path: &Option<PathBuf>) -> error::Result<Conf
pub fn try_drawing(
terminal: &mut tui::terminal::Terminal<tui::backend::CrosstermBackend<std::io::Stdout>>,
app: &mut App, painter: &mut canvas::Painter,
app: &mut AppState, painter: &mut canvas::Painter,
) -> error::Result<()> {
if let Err(err) = painter.draw_data(terminal, app) {
cleanup_terminal(terminal)?;
@ -300,7 +300,7 @@ pub fn panic_hook(panic_info: &PanicInfo<'_>) {
.unwrap();
}
pub fn handle_force_redraws(app: &mut App) {
pub fn handle_force_redraws(app: &mut AppState) {
// Currently we use an Option... because we might want to future-proof this
// if we eventually get widget-specific redrawing!
if app.proc_state.force_update_all {
@ -343,7 +343,7 @@ pub fn handle_force_redraws(app: &mut App) {
}
#[allow(clippy::needless_collect)]
pub fn update_all_process_lists(app: &mut App) {
pub fn update_all_process_lists(app: &mut AppState) {
// According to clippy, I can avoid a collect... but if I follow it,
// I end up conflicting with the borrow checker since app is used within the closure... hm.
if !app.is_frozen {
@ -360,7 +360,7 @@ pub fn update_all_process_lists(app: &mut App) {
}
}
fn update_final_process_list(app: &mut App, widget_id: u64) {
fn update_final_process_list(app: &mut AppState, widget_id: u64) {
let process_states = app
.proc_state
.widget_states
@ -409,7 +409,7 @@ fn update_final_process_list(app: &mut App, widget_id: u64) {
.filter_map(|(_pid, process)| {
if !is_invalid_or_blank {
if let Some(process_filter) = process_filter {
if process_filter.check(&process, is_using_command) {
if process_filter.check(process, is_using_command) {
Some(process)
} else {
None
@ -455,7 +455,7 @@ fn update_final_process_list(app: &mut App, widget_id: u64) {
app.canvas_data.stringified_process_data_map.insert(
widget_id,
stringify_process_data(&proc_widget_state, &finalized_process_data),
stringify_process_data(proc_widget_state, &finalized_process_data),
);
app.canvas_data
.finalized_process_data_map

View File

@ -1,9 +1,7 @@
use regex::Regex;
use serde::{Deserialize, Serialize};
use std::{
borrow::Cow,
collections::{HashMap, HashSet},
path::PathBuf,
str::FromStr,
time::Instant,
};
@ -16,8 +14,6 @@ use crate::{
utils::error::{self, BottomError},
};
use typed_builder::*;
use layout_options::*;
pub mod layout_options;
@ -35,136 +31,75 @@ pub struct Config {
pub net_filter: Option<IgnoreList>,
}
impl Config {
pub fn get_config_as_bytes(&self) -> anyhow::Result<Vec<u8>> {
let mut config_string: Vec<Cow<'_, str>> = Vec::default();
// Top level
config_string.push(CONFIG_TOP_HEAD.into());
config_string.push(toml::to_string_pretty(self)?.into());
Ok(config_string.concat().as_bytes().to_vec())
}
}
#[derive(Clone, Debug, Default, Deserialize, Serialize, TypedBuilder)]
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct ConfigFlags {
#[builder(default, setter(strip_option))]
pub hide_avg_cpu: Option<bool>,
#[builder(default, setter(strip_option))]
pub dot_marker: Option<bool>,
#[builder(default, setter(strip_option))]
pub temperature_type: Option<String>,
#[builder(default, setter(strip_option))]
pub rate: Option<u64>,
#[builder(default, setter(strip_option))]
pub left_legend: Option<bool>,
#[builder(default, setter(strip_option))]
pub current_usage: Option<bool>,
#[builder(default, setter(strip_option))]
pub group_processes: Option<bool>,
#[builder(default, setter(strip_option))]
pub case_sensitive: Option<bool>,
#[builder(default, setter(strip_option))]
pub whole_word: Option<bool>,
#[builder(default, setter(strip_option))]
pub regex: Option<bool>,
#[builder(default, setter(strip_option))]
pub basic: Option<bool>,
#[builder(default, setter(strip_option))]
pub default_time_value: Option<u64>,
#[builder(default, setter(strip_option))]
pub time_delta: Option<u64>,
#[builder(default, setter(strip_option))]
pub autohide_time: Option<bool>,
#[builder(default, setter(strip_option))]
pub hide_time: Option<bool>,
#[builder(default, setter(strip_option))]
pub default_widget_type: Option<String>,
#[builder(default, setter(strip_option))]
pub default_widget_count: Option<u64>,
#[builder(default, setter(strip_option))]
pub use_old_network_legend: Option<bool>,
#[builder(default, setter(strip_option))]
pub hide_table_gap: Option<bool>,
#[builder(default, setter(strip_option))]
pub battery: Option<bool>,
#[builder(default, setter(strip_option))]
pub disable_click: Option<bool>,
#[builder(default, setter(strip_option))]
pub no_write: Option<bool>,
// For built-in colour palettes.
#[builder(default, setter(strip_option))]
pub color: Option<String>,
// This is a huge hack to enable hashmap functionality WITHOUT being able to serializing the field.
// Basically, keep a hashmap in the struct, and convert to a vector every time.
#[builder(default, setter(strip_option))]
#[serde(skip)]
pub search_case_enabled_widgets_map: Option<HashMap<u64, bool>>,
#[builder(default, setter(strip_option))]
pub search_case_enabled_widgets: Option<Vec<WidgetIdEnabled>>,
#[builder(default, setter(strip_option))]
#[serde(skip)]
pub search_whole_word_enabled_widgets_map: Option<HashMap<u64, bool>>,
#[builder(default, setter(strip_option))]
pub search_whole_word_enabled_widgets: Option<Vec<WidgetIdEnabled>>,
#[builder(default, setter(strip_option))]
#[serde(skip)]
pub search_regex_enabled_widgets_map: Option<HashMap<u64, bool>>,
#[builder(default, setter(strip_option))]
pub search_regex_enabled_widgets: Option<Vec<WidgetIdEnabled>>,
// End hack
#[builder(default, setter(strip_option))]
pub mem_as_value: Option<bool>,
#[builder(default, setter(strip_option))]
pub tree: Option<bool>,
#[builder(default, setter(strip_option))]
show_table_scroll_position: Option<bool>,
#[builder(default, setter(strip_option))]
pub process_command: Option<bool>,
#[builder(default, setter(strip_option))]
pub disable_advanced_kill: Option<bool>,
#[builder(default, setter(strip_option))]
pub network_use_bytes: Option<bool>,
#[builder(default, setter(strip_option))]
pub network_use_log: Option<bool>,
#[builder(default, setter(strip_option))]
pub network_use_binary_prefix: Option<bool>,
}
@ -246,13 +181,12 @@ pub struct IgnoreList {
pub fn build_app(
matches: &clap::ArgMatches<'static>, config: &mut Config, widget_layout: &BottomLayout,
default_widget_id: u64, default_widget_type_option: &Option<BottomWidgetType>,
config_path: Option<PathBuf>,
) -> Result<App> {
) -> Result<AppState> {
use BottomWidgetType::*;
let autohide_time = get_autohide_time(&matches, &config);
let default_time_value = get_default_time_value(&matches, &config)
let autohide_time = get_autohide_time(matches, config);
let default_time_value = get_default_time_value(matches, config)
.context("Update 'default_time_value' in your config file.")?;
let use_basic_mode = get_use_basic_mode(&matches, &config);
let use_basic_mode = get_use_basic_mode(matches, config);
// For processes
let is_grouped = get_app_grouping(matches, config);
@ -462,13 +396,11 @@ pub fn build_app(
if let Some(flags) = &mut config.flags {
if flags.case_sensitive.is_none() && !matches.is_present("case_sensitive") {
if let Some(search_case_enabled_widgets) = &flags.search_case_enabled_widgets {
let mapping = HashMap::new();
for widget in search_case_enabled_widgets {
if let Some(proc_widget) = proc_state_map.get_mut(&widget.id) {
proc_widget.process_search_state.is_ignoring_case = !widget.enabled;
}
}
flags.search_case_enabled_widgets_map = Some(mapping);
}
}
@ -476,30 +408,26 @@ pub fn build_app(
if let Some(search_whole_word_enabled_widgets) =
&flags.search_whole_word_enabled_widgets
{
let mapping = HashMap::new();
for widget in search_whole_word_enabled_widgets {
if let Some(proc_widget) = proc_state_map.get_mut(&widget.id) {
proc_widget.process_search_state.is_searching_whole_word = widget.enabled;
}
}
flags.search_whole_word_enabled_widgets_map = Some(mapping);
}
}
if flags.regex.is_none() && !matches.is_present("regex") {
if let Some(search_regex_enabled_widgets) = &flags.search_regex_enabled_widgets {
let mapping = HashMap::new();
for widget in search_regex_enabled_widgets {
if let Some(proc_widget) = proc_state_map.get_mut(&widget.id) {
proc_widget.process_search_state.is_searching_with_regex = widget.enabled;
}
}
flags.search_regex_enabled_widgets_map = Some(mapping);
}
}
}
Ok(App::builder()
Ok(AppState::builder()
.app_config_fields(app_config_fields)
.cpu_state(CpuState::init(cpu_state_map))
.mem_state(MemState::init(mem_state_map))
@ -518,8 +446,6 @@ pub fn build_app(
temp_filter,
net_filter,
})
.config(config.clone())
.config_path(config_path)
.build())
}