diff options
author | Clement Tsang <34804052+ClementTsang@users.noreply.github.com> | 2020-04-01 20:31:43 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-01 20:31:43 -0400 |
commit | 0b1d84fdf590bf8cacc5d0f94b67f63daa9b768a (patch) | |
tree | d2ff261148f9ef21f2e860af43f795df911c5c79 /src | |
parent | c1a19f960fc1b348dd4465fe9a4d698bed229c77 (diff) |
Add modularity to widget placement and inclusion (#95)
Diffstat (limited to 'src')
-rw-r--r-- | src/app.rs | 2695 | ||||
-rw-r--r-- | src/app/data_harvester/processes.rs | 13 | ||||
-rw-r--r-- | src/app/layout_manager.rs | 940 | ||||
-rw-r--r-- | src/app/process_killer.rs | 2 | ||||
-rw-r--r-- | src/canvas.rs | 480 | ||||
-rw-r--r-- | src/canvas/dialogs/dd_dialog.rs | 2 | ||||
-rw-r--r-- | src/canvas/widgets/basic_table_arrows.rs | 34 | ||||
-rw-r--r-- | src/canvas/widgets/cpu_basic.rs | 10 | ||||
-rw-r--r-- | src/canvas/widgets/cpu_graph.rs | 464 | ||||
-rw-r--r-- | src/canvas/widgets/disk_table.rs | 194 | ||||
-rw-r--r-- | src/canvas/widgets/mem_basic.rs | 8 | ||||
-rw-r--r-- | src/canvas/widgets/mem_graph.rs | 181 | ||||
-rw-r--r-- | src/canvas/widgets/network_basic.rs | 12 | ||||
-rw-r--r-- | src/canvas/widgets/network_graph.rs | 244 | ||||
-rw-r--r-- | src/canvas/widgets/process_table.rs | 683 | ||||
-rw-r--r-- | src/canvas/widgets/temp_table.rs | 192 | ||||
-rw-r--r-- | src/constants.rs | 41 | ||||
-rw-r--r-- | src/data_conversion.rs | 54 | ||||
-rw-r--r-- | src/main.rs | 265 | ||||
-rw-r--r-- | src/options.rs | 313 | ||||
-rw-r--r-- | src/options/layout_manager.rs | 3 | ||||
-rw-r--r-- | src/options/layout_options.rs | 307 |
22 files changed, 4751 insertions, 2386 deletions
@@ -1,5 +1,4 @@ -use std::cmp::max; -use std::time::Instant; +use std::{cmp::max, collections::HashMap, time::Instant}; use unicode_segmentation::GraphemeCursor; use unicode_width::{UnicodeWidthChar, UnicodeWidthStr}; @@ -8,64 +7,20 @@ use typed_builder::*; use data_farmer::*; use data_harvester::{processes, temperature}; +use layout_manager::*; -use crate::{canvas, constants, utils::error::Result}; +use crate::{ + canvas, constants, + utils::error::{BottomError, Result}, +}; pub mod data_farmer; pub mod data_harvester; +pub mod layout_manager; mod process_killer; const MAX_SEARCH_LENGTH: usize = 200; -#[derive(Debug, Clone, Copy)] -pub enum WidgetPosition { - Cpu, - CpuLegend, - Mem, - Disk, - Temp, - Network, - NetworkLegend, - Process, - ProcessSearch, - BasicCpu, - BasicMem, - BasicNet, -} - -impl WidgetPosition { - pub fn is_widget_table(self) -> bool { - match self { - WidgetPosition::Disk - | WidgetPosition::Process - | WidgetPosition::ProcessSearch - | WidgetPosition::Temp - | WidgetPosition::CpuLegend => true, - _ => false, - } - } - - pub fn is_widget_graph(self) -> bool { - match self { - WidgetPosition::Cpu | WidgetPosition::Network | WidgetPosition::Mem => true, - _ => false, - } - } - - pub fn get_pretty_name(self) -> String { - use WidgetPosition::*; - match self { - Cpu | BasicCpu | CpuLegend => "CPU", - Mem | BasicMem => "Memory", - Disk => "Disks", - Temp => "Temperature", - Network | BasicNet | NetworkLegend => "Network", - Process | ProcessSearch => "Processes", - } - .to_string() - } -} - #[derive(Debug)] pub enum ScrollDirection { // UP means scrolling up --- this usually DECREMENTS @@ -74,6 +29,12 @@ pub enum ScrollDirection { DOWN, } +impl Default for ScrollDirection { + fn default() -> Self { + ScrollDirection::DOWN + } +} + #[derive(Debug)] pub enum CursorDirection { LEFT, @@ -85,28 +46,52 @@ pub enum CursorDirection { pub struct AppScrollWidgetState { pub current_scroll_position: u64, pub previous_scroll_position: u64, + pub scroll_direction: ScrollDirection, } -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, +#[derive(Default)] +pub struct AppDeleteDialogState { + pub is_showing_dd: bool, + pub is_on_yes: bool, // Defaults to "No" } -impl Default for AppScrollState { +pub enum AppHelpCategory { + General, + Process, + Search, +} + +pub struct AppHelpDialogState { + pub is_showing_help: bool, + pub current_category: AppHelpCategory, +} + +impl Default for AppHelpDialogState { 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(), + AppHelpDialogState { + is_showing_help: false, + current_category: AppHelpCategory::General, } } } +/// AppConfigFields is meant to cover basic fields that would normally be set +/// by config files or launch options. +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 show_disabled_data: bool, + pub use_basic_mode: bool, + pub default_time_value: u64, + pub time_interval: u64, + pub hide_time: bool, + pub autohide_time: bool, +} + /// AppSearchState deals with generic searching (I might do this in the future). pub struct AppSearchState { pub is_enabled: bool, @@ -186,138 +171,299 @@ impl ProcessSearchState { } } -#[derive(Default)] -pub struct AppDeleteDialogState { - pub is_showing_dd: bool, - pub is_on_yes: bool, // Defaults to "No" +pub struct ProcWidgetState { + pub process_search_state: ProcessSearchState, + pub is_grouped: bool, + pub scroll_state: AppScrollWidgetState, + pub process_sorting_type: processes::ProcessSorting, + pub process_sorting_reverse: bool, } -pub enum AppHelpCategory { - General, - Process, - Search, -} +impl ProcWidgetState { + pub fn init( + is_case_sensitive: bool, is_match_whole_word: bool, is_use_regex: bool, is_grouped: bool, + ) -> Self { + let mut process_search_state = ProcessSearchState::default(); + if is_case_sensitive { + // By default it's off + process_search_state.search_toggle_ignore_case(); + } + if is_match_whole_word { + process_search_state.search_toggle_whole_word(); + } + if is_use_regex { + process_search_state.search_toggle_regex(); + } -pub struct AppHelpDialogState { - pub is_showing_help: bool, - pub current_category: AppHelpCategory, -} + ProcWidgetState { + process_search_state, + is_grouped, + scroll_state: AppScrollWidgetState::default(), + process_sorting_type: processes::ProcessSorting::CPU, + process_sorting_reverse: true, + } + } -impl Default for AppHelpDialogState { - fn default() -> Self { - AppHelpDialogState { - is_showing_help: false, - current_category: AppHelpCategory::General, + pub fn get_cursor_position(&self) -> usize { + self.process_search_state + .search_state + .grapheme_cursor + .cur_cursor() + } + + pub fn get_char_cursor_position(&self) -> usize { + self.process_search_state.search_state.char_cursor_position + } + + pub fn is_search_enabled(&self) -> bool { + self.process_search_state.search_state.is_enabled + } + + pub fn get_current_search_query(&self) -> &String { + &self.process_search_state.search_state.current_search_query + } + + pub fn update_regex(&mut self) { + if self + .process_search_state + .search_state + .current_search_query + .is_empty() + { + self.process_search_state.search_state.is_invalid_search = false; + self.process_search_state.search_state.is_blank_search = true; + } else { + let regex_string = &self.process_search_state.search_state.current_search_query; + let escaped_regex: String; + let final_regex_string = &format!( + "{}{}{}{}", + if self.process_search_state.is_searching_whole_word { + "^" + } else { + "" + }, + if self.process_search_state.is_ignoring_case { + "(?i)" + } else { + "" + }, + if !self.process_search_state.is_searching_with_regex { + escaped_regex = regex::escape(regex_string); + &escaped_regex + } else { + regex_string + }, + if self.process_search_state.is_searching_whole_word { + "$" + } else { + "" + }, + ); + + let new_regex = regex::Regex::new(final_regex_string); + self.process_search_state.search_state.is_blank_search = false; + self.process_search_state.search_state.is_invalid_search = new_regex.is_err(); + + self.process_search_state.search_state.current_regex = Some(new_regex); } + self.scroll_state.previous_scroll_position = 0; + self.scroll_state.current_scroll_position = 0; + } + + pub fn clear_search(&mut self) { + self.process_search_state.search_state.reset(); + } + + pub fn search_walk_forward(&mut self, start_position: usize) { + self.process_search_state + .search_state + .grapheme_cursor + .next_boundary( + &self.process_search_state.search_state.current_search_query[start_position..], + start_position, + ) + .unwrap(); + } + + pub fn search_walk_back(&mut self, start_position: usize) { + self.process_search_state + .search_state + .grapheme_cursor + .prev_boundary( + &self.process_search_state.search_state.current_search_query[..start_position], + 0, + ) + .unwrap(); } } -/// AppConfigFields is meant to cover basic fields that would normally be set -/// by config files or launch options. -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 show_disabled_data: bool, - pub use_basic_mode: bool, - pub default_time_value: u64, - pub time_interval: u64, - pub hide_time: bool, - pub autohide_time: bool, +pub struct ProcState { + pub widget_states: HashMap<u64, ProcWidgetState>, + pub force_update: Option<u64>, + pub force_update_all: bool, } -/// Network specific -pub struct NetState { - pub is_showing_tray: bool, - pub is_showing_rx: bool, - pub is_showing_tx: bool, - pub zoom_level: f64, +impl ProcState { + pub fn init(widget_states: HashMap<u64, ProcWidgetState>) -> Self { + ProcState { + widget_states, + force_update: None, + force_update_all: false, + } + } +} + +pub struct NetWidgetState { pub current_display_time: u64, - pub force_update: bool, pub autohide_timer: Option<Instant>, } -impl NetState { +impl NetWidgetState { pub fn init(current_display_time: u64, autohide_timer: Option<Instant>) -> Self { - NetState { - is_showing_tray: false, - is_showing_rx: true, - is_showing_tx: true, - zoom_level: 100.0, + NetWidgetState { current_display_time, - force_update: false, autohide_timer, } } } -/// CPU specific -pub struct CpuState { +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 struct CpuWidgetState { + pub current_display_time: u64, + pub is_legend_hidden: bool, pub is_showing_tray: bool, - pub zoom_level: f64, pub core_show_vec: Vec<bool>, - pub num_cpus_shown: u64, - pub current_display_time: u64, - pub force_update: bool, + pub num_cpus_shown: usize, pub autohide_timer: Option<Instant>, + pub scroll_state: AppScrollWidgetState, } -impl CpuState { +impl CpuWidgetState { pub fn init(current_display_time: u64, autohide_timer: Option<Instant>) -> Self { - CpuState { + CpuWidgetState { + current_display_time, + is_legend_hidden: false, is_showing_tray: false, - zoom_level: 100.0, core_show_vec: Vec::new(), num_cpus_shown: 0, - current_display_time, - force_update: false, autohide_timer, + scroll_state: AppScrollWidgetState::default(), } } } -/// Memory specific -pub struct MemState { - pub is_showing_tray: bool, - pub is_showing_ram: bool, - pub is_showing_swap: bool, - pub zoom_level: f64, +pub struct CpuState { + pub force_update: Option<u64>, + pub widget_states: HashMap<u64, CpuWidgetState>, + pub num_cpus_total: usize, +} + +impl CpuState { + pub fn init(widget_states: HashMap<u64, CpuWidgetState>) -> Self { + CpuState { + force_update: None, + widget_states, + num_cpus_total: 0, + } + } +} + +pub struct MemWidgetState { pub current_display_time: u64, - pub force_update: bool, pub autohide_timer: Option<Instant>, } -impl MemState { +impl MemWidgetState { pub fn init(current_display_time: u64, autohide_timer: Option<Instant>) -> Self { - MemState { - is_showing_tray: false, - is_showing_ram: true, - is_showing_swap: true, - zoom_level: 100.0, + MemWidgetState { current_display_time, - force_update: false, autohide_timer, } } } -#[derive(TypedBuilder)] -pub struct App { - #[builder(default=processes::ProcessSorting::CPU, setter(skip))] - pub process_sorting_type: processes::ProcessSorting, +pub struct MemState { + pub force_update: Option<u64>, + pub widget_states: HashMap<u64, MemWidgetState>, +} - #[builder(default = true, setter(skip))] - pub process_sorting_reverse: bool, +impl MemState { + pub fn init(widget_states: HashMap<u64, MemWidgetState>) -> Self { + MemState { + force_update: None, + widget_states, + } + } +} - #[builder(default = false, setter(skip))] - pub force_update_processes: bool, +pub struct TempWidgetState { + pub scroll_state: AppScrollWidgetState, +} - #[builder(default, setter(skip))] - pub app_scroll_positions: AppScrollState, +impl TempWidgetState { + pub fn init() -> Self { + TempWidgetState { + scroll_state: AppScrollWidgetState::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 struct DiskWidgetState { + pub scroll_state: AppScrollWidgetState, +} + +impl DiskWidgetState { + pub fn init() -> Self { + DiskWidgetState { + scroll_state: AppScrollWidgetState::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 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, +} + +#[derive(TypedBuilder)] +pub struct App { #[builder(default = false, setter(skip))] awaiting_second_char: bool, @@ -339,16 +485,10 @@ pub struct App { #[builder(default, setter(skip))] pub canvas_data: canvas::DisplayableData, - #[builder(default = false)] - enable_grouping: bool, - #[builder(default, setter(skip))] pub data_collection: DataCollection, #[builder(default, setter(skip))] - pub process_search_state: ProcessSearchState, - - #[builder(default, setter(skip))] pub delete_dialog_state: AppDeleteDialogState, #[builder(default, setter(skip))] @@ -363,10 +503,15 @@ pub struct App { pub cpu_state: CpuState, pub mem_state: MemState, pub net_state: NetState, + pub proc_state: ProcState, + pub temp_state: TempState, + pub disk_state: DiskState, + + pub basic_table_widget_state: Option<BasicTableWidgetState>, pub app_config_fields: AppConfigFields, - pub current_widget_selected: WidgetPosition, - pub previous_basic_table_selected: WidgetPosition, + pub widget_map: HashMap<u64, BottomWidget>, + pub current_widget: BottomWidget, } impl App { @@ -378,9 +523,22 @@ impl App { self.help_dialog_state.is_showing_help = false; self.delete_dialog_state.is_showing_dd = false; - // Close search and reset it - self.process_search_state.search_state.reset(); - self.force_update_processes = true; + // Close all searches and reset it + self.proc_state + .widget_states + .values_mut() + .for_each(|state| { + state.process_search_state.search_state.reset(); + }); + self.proc_state.force_update_all = true; + + // Reset all CPU filter states + self.cpu_state.widget_states.values_mut().for_each(|state| { + for show_vec_state in &mut state.core_show_vec { + *show_vec_state = true; + } + state.num_cpus_shown = state.core_show_vec.len(); + }); // Clear current delete list self.to_delete_process_list = None; @@ -408,59 +566,136 @@ impl App { self.to_delete_process_list = None; self.dd_err = None; } else if self.is_filtering_or_searching() { - match self.current_widget_selected { - WidgetPosition::Cpu | WidgetPosition::CpuLegend => { - self.cpu_state.is_showing_tray = false; - if self - .app_scroll_positions - .cpu_scroll_state - .current_scroll_position - >= self.cpu_state.num_cpus_shown + match self.current_widget.widget_type { + BottomWidgetType::Cpu => { + if let Some(cpu_widget_state) = self + .cpu_state + .widget_states + .get_mut(&self.current_widget.widget_id) { - let new_position = max(0, self.cpu_state.num_cpus_shown as i64 - 1) as u64; - self.app_scroll_positions - .cpu_scroll_state - .current_scroll_position = new_position; - self.app_scroll_positions - .cpu_scroll_state - .previous_scroll_position = 0; + cpu_widget_state.is_showing_tray = false; + if cpu_widget_state.scroll_state.current_scroll_position + >= cpu_widget_state.num_cpus_shown as u64 + { + let new_position = + max(0, cpu_widget_state.num_cpus_shown as i64 - 1) as u64; + cpu_widget_state.scroll_state.current_scroll_position = new_position; + cpu_widget_state.scroll_state.previous_scroll_position = 0; + } } } - WidgetPosition::Process | WidgetPosition::ProcessSearch => { - if self.process_search_state.search_state.is_enabled { - self.current_widget_selected = WidgetPosition::Process; - self.process_search_state.search_state.is_enabled = false; + BottomWidgetType::CpuLegend => { + if let Some(cpu_widget_state) = self + .cpu_state + .widget_states + .get_mut(&(self.current_widget.widget_id - 1)) + { + cpu_widget_state.is_showing_tray = false; + if cpu_widget_state.scroll_state.current_scroll_position + >= cpu_widget_state.num_cpus_shown as u64 + { + let new_position = + max(0, cpu_widget_state.num_cpus_shown as i64 - 1) as u64; + cpu_widget_state.scroll_state.current_scroll_position = new_position; + cpu_widget_state.scroll_state.previous_scroll_position = 0; + } } } - WidgetPosition::Mem => { - self.mem_state.is_showing_tray = false; + BottomWidgetType::Proc => { + if let Some(current_proc_state) = self + .proc_state + .widget_states + .get_mut(&self.current_widget.widget_id) + { + if current_proc_state.is_search_enabled() { + current_proc_state + .process_search_state + .search_state + .is_enabled = false; + } + } } - WidgetPosition::Network => { - self.net_state.is_showing_tray = false; + BottomWidgetType::ProcSearch => { + if let Some(current_proc_state) = self + .proc_state + .widget_states + .get_mut(&(self.current_widget.widget_id - 1)) + { + if current_proc_state.is_search_enabled() { + current_proc_state + .process_search_state + .search_state + .is_enabled = false; + self.move_widget_selection_up(); + } + } } _ => {} } } else if self.is_expanded { self.is_expanded = false; self.is_resized = true; - if self.app_config_fields.use_basic_mode { - self.current_widget_selected = match self.current_widget_selected { - WidgetPosition::Cpu | WidgetPosition::CpuLegend => WidgetPosition::BasicCpu, - WidgetPosition::Mem => WidgetPosition::BasicMem, - WidgetPosition::Network => WidgetPosition::BasicNet, - _ => self.current_widget_selected, - } - } } } + pub fn is_in_search_widget(&self) -> bool { + matches!( + self.current_widget.widget_type, + BottomWidgetType::ProcSearch + ) + } + fn is_filtering_or_searching(&self) -> bool { - match self.current_widget_selected { - WidgetPosition::Cpu | WidgetPosition::CpuLegend => self.cpu_state.is_showing_tray, - // WidgetPosition::Mem => self.mem_state.is_showing_tray, - // WidgetPosition::Network => self.net_state.is_showing_tray, - WidgetPosition::Process | WidgetPosition::ProcessSearch => { - self.process_search_state.search_state.is_enabled + match self.current_widget.widget_type { + BottomWidgetType::Cpu => { + if let Some(cpu_widget_state) = self + .cpu_state + .widget_states + .get(&self.current_widget.widget_id) + { + cpu_widget_state.is_showing_tray + } else { + false + } + } + BottomWidgetType::CpuLegend => { + if let Some(cpu_widget_state) = self + .cpu_state + .widget_states + .get(&(self.current_widget.widget_id - 1)) + { + cpu_widget_state.is_showing_tray + } else { + false + } + } + BottomWidgetType::Proc => { + if let Some(proc_widget_state) = self + .proc_state + .widget_states + .get(&self.current_widget.widget_id) + { + proc_widget_state + .process_search_state + .search_state + .is_enabled + } else { + false + } + } + BottomWidgetType::ProcSearch => { + if let Some(proc_widget_state) = self + .proc_state + .widget_states + .get(&(self.current_widget.widget_id - 1)) + { + proc_widget_state + .process_search_state + .search_state + .is_enabled + } else { + false + } } _ => false, } @@ -475,208 +710,210 @@ impl App { self.help_dialog_state.is_showing_help || self.delete_dialog_state.is_showing_dd } - pub fn toggle_grouping(&mut self) { + pub fn on_tab(&mut self) { // Disallow usage whilst in a dialog and only in processes - if !self.is_in_dialog() { - if let WidgetPosition::Process = self.current_widget_selected { - self.enable_grouping = !(self.enable_grouping); - self.force_update_processes = true; - } - } - } - pub fn on_tab(&mut self) { - match self.current_widget_selected { - WidgetPosition::Process => { - self.toggle_grouping(); - if self.is_grouped() { - self.search_with_name(); + let is_in_search_widget = self.is_in_search_widget(); + if !self.is_in_dialog() { + if let Some(proc_widget_state) = self + .proc_state + .widget_states + .get_mut(&(self.current_widget.widget_id - 1)) + { + if is_in_search_widget { + if !proc_widget_state.is_grouped { + if proc_widget_state.process_search_state.is_searching_with_pid { + self.search_with_name(); + } else { + self.search_with_pid(); + } + } } else { - self.force_update_processes = true; - } - } - WidgetPosition::ProcessSearch => { - if !self.is_grouped() { - if self.process_search_state.is_searching_with_pid { + // Toggles process widget grouping state + proc_widget_state.is_grouped = !(proc_widget_state.is_grouped); + if proc_widget_state.is_grouped { self.search_with_name(); - } else { - self.search_with_pid(); } } } - _ => {} } } - pub fn is_grouped(&self) -> bool { - self.enable_grouping + /// I don't like this, but removing it causes a bunch of breakage. + /// Use ``proc_widget_state.is_grouped`` if possible! + pub fn is_grouped(&self, widget_id: u64) -> bool { + if let Some(proc_widget_state) = self.proc_state.widget_states.get(&widget_id) { + proc_widget_state.is_grouped + } else { + false + } } + /// "On space" if we don't want to treat is as a character. pub fn on_space(&mut self) { - match self.current_widget_selected { - WidgetPosition::CpuLegend => { - let curr_posn = self - .app_scroll_positions - .cpu_scroll_state - .current_scroll_position; - if self.cpu_state.is_showing_tray + if let BottomWidgetType::CpuLegend = self.current_widget.widget_type { + if let Some(cpu_widget_state) = self + .cpu_state + .widget_states + .get_mut(&(self.current_widget.widget_id - 1)) + { + let curr_posn = cpu_widget_state.scroll_state.current_scroll_position; + if cpu_widget_state.is_showing_tray && curr_posn < self.data_collection.cpu_harvest.len() as u64 { - self.cpu_state.core_show_vec[curr_posn as usize] = - !self.cpu_state.core_show_vec[curr_posn as usize]; + cpu_widget_state.core_show_vec[curr_posn as usize] = + !cpu_widget_state.core_show_vec[curr_posn as usize]; if !self.app_config_fields.show_disabled_data { - if !self.cpu_state.core_show_vec[curr_posn as usize] { - self.cpu_state.num_cpus_shown -= 1; + if !cpu_widget_state.core_show_vec[c |