From 8534d42f1be01cf8da8176036112a9405bd03217 Mon Sep 17 00:00:00 2001 From: ClementTsang Date: Mon, 27 Apr 2020 13:48:56 -0400 Subject: [PATCH 1/4] refactor: separate state to different file --- README.md | 4 +- src/app.rs | 445 +-------------------------------------------- src/app/states.rs | 448 ++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 1 + src/options.rs | 14 ++ 5 files changed, 467 insertions(+), 445 deletions(-) create mode 100644 src/app/states.rs diff --git a/README.md b/README.md index 137f682d..3171a8fa 100644 --- a/README.md +++ b/README.md @@ -418,8 +418,8 @@ and get the following CPU donut: ### Battery You can get battery statistics (charge, time to fill/discharge, consumption in watts, and battery health) via the battery widget. -Since this is only useful for devices like laptops, it is off by default. Currently, the only way to use it is to set it -as a widget via [layouts](#layout). + +Since this is only useful for devices like laptops, it is off by default. You can either enable the widget in the default layout via the `--battery` flag, or by specifying the widget in a [layout](#layout). So with this slightly silly layout: diff --git a/src/app.rs b/src/app.rs index 19169087..227f0231 100644 --- a/src/app.rs +++ b/src/app.rs @@ -3,13 +3,12 @@ use std::{cmp::max, collections::HashMap, time::Instant}; use unicode_segmentation::GraphemeCursor; use unicode_width::{UnicodeWidthChar, UnicodeWidthStr}; -use tui::widgets::TableState; - use typed_builder::*; use data_farmer::*; use data_harvester::{processes, temperature}; use layout_manager::*; +pub use states::*; use crate::{ canvas, constants, @@ -20,60 +19,10 @@ pub mod data_farmer; pub mod data_harvester; pub mod layout_manager; mod process_killer; +pub mod states; const MAX_SEARCH_LENGTH: usize = 200; -#[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: u64, - pub previous_scroll_position: u64, - pub scroll_direction: ScrollDirection, - pub table_state: TableState, -} - -#[derive(Default)] -pub struct AppDeleteDialogState { - pub is_showing_dd: bool, - pub is_on_yes: bool, // Defaults to "No" -} - -pub struct AppHelpDialogState { - pub is_showing_help: bool, - pub scroll_state: ParagraphScrollState, - pub index_shortcuts: Vec, -} - -impl Default for AppHelpDialogState { - fn default() -> Self { - AppHelpDialogState { - is_showing_help: false, - scroll_state: ParagraphScrollState::default(), - index_shortcuts: vec![0; constants::HELP_TEXT.len()], - } - } -} - /// AppConfigFields is meant to cover basic fields that would normally be set /// by config files or launch options. pub struct AppConfigFields { @@ -93,396 +42,6 @@ pub struct AppConfigFields { pub table_gap: u16, } -/// AppSearchState deals with generic searching (I might do this in the future). -pub struct AppSearchState { - pub is_enabled: bool, - pub current_search_query: String, - pub current_regex: Option>, - pub is_blank_search: bool, - pub is_invalid_search: bool, - pub grapheme_cursor: GraphemeCursor, - pub cursor_direction: CursorDirection, - pub cursor_bar: usize, - /// This represents the position in terms of CHARACTERS, not graphemes - pub char_cursor_position: usize, -} - -impl Default for AppSearchState { - fn default() -> Self { - AppSearchState { - is_enabled: false, - current_search_query: String::default(), - current_regex: None, - is_invalid_search: false, - is_blank_search: true, - grapheme_cursor: GraphemeCursor::new(0, 0, true), - cursor_direction: CursorDirection::RIGHT, - cursor_bar: 0, - char_cursor_position: 0, - } - } -} - -impl AppSearchState { - /// Returns a reset but still enabled app search state - pub fn reset(&mut self) { - *self = AppSearchState { - is_enabled: self.is_enabled, - ..AppSearchState::default() - } - } - - pub fn is_invalid_or_blank_search(&self) -> bool { - self.is_blank_search || self.is_invalid_search - } -} - -/// ProcessSearchState only deals with process' search's current settings and state. -pub struct ProcessSearchState { - pub search_state: AppSearchState, - pub is_searching_with_pid: bool, - pub is_ignoring_case: bool, - pub is_searching_whole_word: bool, - pub is_searching_with_regex: bool, -} - -impl Default for ProcessSearchState { - fn default() -> Self { - ProcessSearchState { - search_state: AppSearchState::default(), - is_searching_with_pid: false, - is_ignoring_case: true, - is_searching_whole_word: false, - is_searching_with_regex: false, - } - } -} - -impl ProcessSearchState { - pub fn search_toggle_ignore_case(&mut self) { - self.is_ignoring_case = !self.is_ignoring_case; - } - - pub fn search_toggle_whole_word(&mut self) { - self.is_searching_whole_word = !self.is_searching_whole_word; - } - - pub fn search_toggle_regex(&mut self) { - self.is_searching_with_regex = !self.is_searching_with_regex; - } -} - -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, -} - -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(); - } - - ProcWidgetState { - process_search_state, - is_grouped, - scroll_state: AppScrollWidgetState::default(), - process_sorting_type: processes::ProcessSorting::CPU, - process_sorting_reverse: true, - } - } - - 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(); - } -} - -pub struct ProcState { - pub widget_states: HashMap, - pub force_update: Option, - pub force_update_all: bool, -} - -impl ProcState { - pub fn init(widget_states: HashMap) -> Self { - ProcState { - widget_states, - force_update: None, - force_update_all: false, - } - } -} - -pub struct NetWidgetState { - pub current_display_time: u64, - pub autohide_timer: Option, -} - -impl NetWidgetState { - pub fn init(current_display_time: u64, autohide_timer: Option) -> Self { - NetWidgetState { - current_display_time, - autohide_timer, - } - } -} - -pub struct NetState { - pub force_update: Option, - pub widget_states: HashMap, -} - -impl NetState { - pub fn init(widget_states: HashMap) -> 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 core_show_vec: Vec, - pub num_cpus_shown: usize, - pub autohide_timer: Option, - pub scroll_state: AppScrollWidgetState, -} - -impl CpuWidgetState { - pub fn init(current_display_time: u64, autohide_timer: Option) -> Self { - CpuWidgetState { - current_display_time, - is_legend_hidden: false, - is_showing_tray: false, - core_show_vec: Vec::new(), - num_cpus_shown: 0, - autohide_timer, - scroll_state: AppScrollWidgetState::default(), - } - } -} - -pub struct CpuState { - pub force_update: Option, - pub widget_states: HashMap, - pub num_cpus_total: usize, -} - -impl CpuState { - pub fn init(widget_states: HashMap) -> Self { - CpuState { - force_update: None, - widget_states, - num_cpus_total: 0, - } - } -} - -pub struct MemWidgetState { - pub current_display_time: u64, - pub autohide_timer: Option, -} - -impl MemWidgetState { - pub fn init(current_display_time: u64, autohide_timer: Option) -> Self { - MemWidgetState { - current_display_time, - autohide_timer, - } - } -} - -pub struct MemState { - pub force_update: Option, - pub widget_states: HashMap, -} - -impl MemState { - pub fn init(widget_states: HashMap) -> Self { - MemState { - force_update: None, - widget_states, - } - } -} - -pub struct TempWidgetState { - pub scroll_state: AppScrollWidgetState, -} - -impl TempWidgetState { - pub fn init() -> Self { - TempWidgetState { - scroll_state: AppScrollWidgetState::default(), - } - } -} - -pub struct TempState { - pub widget_states: HashMap, -} - -impl TempState { - pub fn init(widget_states: HashMap) -> 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, -} - -impl DiskState { - pub fn init(widget_states: HashMap) -> 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(Default)] -pub struct BatteryWidgetState { - pub currently_selected_battery_index: usize, -} - -pub struct BatteryState { - pub widget_states: HashMap, -} - -impl BatteryState { - pub fn init(widget_states: HashMap) -> Self { - BatteryState { widget_states } - } -} - -#[derive(Default)] -pub struct ParagraphScrollState { - pub current_scroll_index: u16, - pub max_scroll_index: u16, -} - #[derive(TypedBuilder)] pub struct App { #[builder(default = false, setter(skip))] diff --git a/src/app/states.rs b/src/app/states.rs new file mode 100644 index 00000000..ca181502 --- /dev/null +++ b/src/app/states.rs @@ -0,0 +1,448 @@ +use std::{collections::HashMap, time::Instant}; + +use unicode_segmentation::GraphemeCursor; + +use tui::widgets::TableState; + +use crate::{app::layout_manager::BottomWidgetType, constants, data_harvester::processes}; + +#[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: u64, + pub previous_scroll_position: u64, + pub scroll_direction: ScrollDirection, + pub table_state: TableState, +} + +#[derive(Default)] +pub struct AppDeleteDialogState { + pub is_showing_dd: bool, + pub is_on_yes: bool, // Defaults to "No" +} + +pub struct AppHelpDialogState { + pub is_showing_help: bool, + pub scroll_state: ParagraphScrollState, + pub index_shortcuts: Vec, +} + +impl Default for AppHelpDialogState { + fn default() -> Self { + AppHelpDialogState { + is_showing_help: false, + scroll_state: ParagraphScrollState::default(), + index_shortcuts: vec![0; constants::HELP_TEXT.len()], + } + } +} + +/// AppSearchState deals with generic searching (I might do this in the future). +pub struct AppSearchState { + pub is_enabled: bool, + pub current_search_query: String, + pub current_regex: Option>, + pub is_blank_search: bool, + pub is_invalid_search: bool, + pub grapheme_cursor: GraphemeCursor, + pub cursor_direction: CursorDirection, + pub cursor_bar: usize, + /// This represents the position in terms of CHARACTERS, not graphemes + pub char_cursor_position: usize, +} + +impl Default for AppSearchState { + fn default() -> Self { + AppSearchState { + is_enabled: false, + current_search_query: String::default(), + current_regex: None, + is_invalid_search: false, + is_blank_search: true, + grapheme_cursor: GraphemeCursor::new(0, 0, true), + cursor_direction: CursorDirection::RIGHT, + cursor_bar: 0, + char_cursor_position: 0, + } + } +} + +impl AppSearchState { + /// Returns a reset but still enabled app search state + pub fn reset(&mut self) { + *self = AppSearchState { + is_enabled: self.is_enabled, + ..AppSearchState::default() + } + } + + pub fn is_invalid_or_blank_search(&self) -> bool { + self.is_blank_search || self.is_invalid_search + } +} + +/// ProcessSearchState only deals with process' search's current settings and state. +pub struct ProcessSearchState { + pub search_state: AppSearchState, + pub is_searching_with_pid: bool, + pub is_ignoring_case: bool, + pub is_searching_whole_word: bool, + pub is_searching_with_regex: bool, +} + +impl Default for ProcessSearchState { + fn default() -> Self { + ProcessSearchState { + search_state: AppSearchState::default(), + is_searching_with_pid: false, + is_ignoring_case: true, + is_searching_whole_word: false, + is_searching_with_regex: false, + } + } +} + +impl ProcessSearchState { + pub fn search_toggle_ignore_case(&mut self) { + self.is_ignoring_case = !self.is_ignoring_case; + } + + pub fn search_toggle_whole_word(&mut self) { + self.is_searching_whole_word = !self.is_searching_whole_word; + } + + pub fn search_toggle_regex(&mut self) { + self.is_searching_with_regex = !self.is_searching_with_regex; + } +} + +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, +} + +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(); + } + + ProcWidgetState { + process_search_state, + is_grouped, + scroll_state: AppScrollWidgetState::default(), + process_sorting_type: processes::ProcessSorting::CPU, + process_sorting_reverse: true, + } + } + + 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(); + } +} + +pub struct ProcState { + pub widget_states: HashMap, + pub force_update: Option, + pub force_update_all: bool, +} + +impl ProcState { + pub fn init(widget_states: HashMap) -> Self { + ProcState { + widget_states, + force_update: None, + force_update_all: false, + } + } +} + +pub struct NetWidgetState { + pub current_display_time: u64, + pub autohide_timer: Option, +} + +impl NetWidgetState { + pub fn init(current_display_time: u64, autohide_timer: Option) -> Self { + NetWidgetState { + current_display_time, + autohide_timer, + } + } +} + +pub struct NetState { + pub force_update: Option, + pub widget_states: HashMap, +} + +impl NetState { + pub fn init(widget_states: HashMap) -> 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 core_show_vec: Vec, + pub num_cpus_shown: usize, + pub autohide_timer: Option, + pub scroll_state: AppScrollWidgetState, +} + +impl CpuWidgetState { + pub fn init(current_display_time: u64, autohide_timer: Option) -> Self { + CpuWidgetState { + current_display_time, + is_legend_hidden: false, + is_showing_tray: false, + core_show_vec: Vec::new(), + num_cpus_shown: 0, + autohide_timer, + scroll_state: AppScrollWidgetState::default(), + } + } +} + +pub struct CpuState { + pub force_update: Option, + pub widget_states: HashMap, + pub num_cpus_total: usize, +} + +impl CpuState { + pub fn init(widget_states: HashMap) -> Self { + CpuState { + force_update: None, + widget_states, + num_cpus_total: 0, + } + } +} + +pub struct MemWidgetState { + pub current_display_time: u64, + pub autohide_timer: Option, +} + +impl MemWidgetState { + pub fn init(current_display_time: u64, autohide_timer: Option) -> Self { + MemWidgetState { + current_display_time, + autohide_timer, + } + } +} + +pub struct MemState { + pub force_update: Option, + pub widget_states: HashMap, +} + +impl MemState { + pub fn init(widget_states: HashMap) -> Self { + MemState { + force_update: None, + widget_states, + } + } +} + +pub struct TempWidgetState { + pub scroll_state: AppScrollWidgetState, +} + +impl TempWidgetState { + pub fn init() -> Self { + TempWidgetState { + scroll_state: AppScrollWidgetState::default(), + } + } +} + +pub struct TempState { + pub widget_states: HashMap, +} + +impl TempState { + pub fn init(widget_states: HashMap) -> 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, +} + +impl DiskState { + pub fn init(widget_states: HashMap) -> 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(Default)] +pub struct BatteryWidgetState { + pub currently_selected_battery_index: usize, +} + +pub struct BatteryState { + pub widget_states: HashMap, +} + +impl BatteryState { + pub fn init(widget_states: HashMap) -> Self { + BatteryState { widget_states } + } +} + +#[derive(Default)] +pub struct ParagraphScrollState { + pub current_scroll_index: u16, + pub max_scroll_index: u16, +} diff --git a/src/main.rs b/src/main.rs index a74c0485..eecdd7da 100644 --- a/src/main.rs +++ b/src/main.rs @@ -92,6 +92,7 @@ fn get_matches() -> clap::ArgMatches<'static> { (@arg DEFAULT_WIDGET_COUNT: --default_widget_count +takes_value "Which number of the selected widget type to select, from left to right, top to bottom. Defaults to 1.") (@arg USE_OLD_NETWORK_LEGEND: --use_old_network_legend "Use the older (pre-0.4) network widget legend.") (@arg HIDE_TABLE_GAP: --hide_table_gap "Hides the spacing between the table headers and entries.") + (@arg BATTERY: --battery "Shows the battery widget in default or basic mode. No effect on custom layouts.") ) .get_matches() } diff --git a/src/options.rs b/src/options.rs index b879d9ca..7351f4c4 100644 --- a/src/options.rs +++ b/src/options.rs @@ -42,6 +42,7 @@ pub struct ConfigFlags { pub default_widget_count: Option, pub use_old_network_legend: Option, pub hide_table_gap: Option, + pub battery: Option, } #[derive(Default, Deserialize)] @@ -636,3 +637,16 @@ pub fn get_hide_table_gap(matches: &clap::ArgMatches<'static>, config: &Config) } false } + +pub fn get_use_battery(matches: &clap::ArgMatches<'static>, config: &Config) -> bool { + if matches.is_present("BATTERY") { + return true; + } else if let Some(flags) = &config.flags { + if let Some(battery) = flags.battery { + if battery { + return true; + } + } + } + false +} From 8e4f6a3a02401bd7625e4ce7e087adc0750a538e Mon Sep 17 00:00:00 2001 From: ClementTsang Date: Mon, 27 Apr 2020 15:52:39 -0400 Subject: [PATCH 2/4] feature: add battery flag --- README.md | 9 +- src/app.rs | 2 + src/app/layout_manager.rs | 317 +++++++++++++++-------- src/canvas.rs | 18 +- src/canvas/widgets/basic_table_arrows.rs | 52 ++-- src/canvas/widgets/battery_display.rs | 36 ++- src/canvas/widgets/temp_table.rs | 6 +- src/options.rs | 6 +- 8 files changed, 301 insertions(+), 145 deletions(-) diff --git a/README.md b/README.md index 3171a8fa..06db149a 100644 --- a/README.md +++ b/README.md @@ -143,20 +143,21 @@ Run using `btm`. -s, --show_disabled_data Shows disabled CPU entries in the CPU legend -b, --basic Enables basic mode, removing charts and condensing data --autohide_time Automatically hide the time scaling in graphs after being shown for a brief moment when - zoomed in/out. If time is disabled via --hide_time then this will have no effect. + zoomed in/out. If time is disabled via --hide_time then this will have no effect --use_old_network_legend Use the older (pre-0.4) network legend which is separate from the network chart --hide_table_gap Hides the spacing between table headers and data + --battery Displays the battery widget for default and basic layouts ``` ### Options ``` -r, --rate Set the refresh rate in milliseconds [default: 1000] --C, --config Use the specified config file; if it does not exist it is automatically created +-C, --config Use the specified config file; if it does not exist it is automatically created [default: see section on config files] -t, --default_time_value Sets the default time interval for charts in milliseconds [default: 60000] -d, --time_delta Sets the default amount each zoom in/out action changes by in milliseconds [default: 15000] - --default_widget_count Which number of the selected widget type to select, from left to right, top to bottom. Defaults to 1. - --default_widget_type The default widget type to select by default. + --default_widget_count Which number of the selected widget type to select, from left to right, top to bottom [default: 1] + --default_widget_type The default widget type to select by default [default: "process"] ``` ### Keybindings diff --git a/src/app.rs b/src/app.rs index 227f0231..b312bc2a 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1213,6 +1213,7 @@ impl App { | BottomWidgetType::Proc | BottomWidgetType::ProcSearch | BottomWidgetType::Disk + | BottomWidgetType::Battery if self.basic_table_widget_state.is_some() => { if let Some(basic_table_widget_state) = @@ -1311,6 +1312,7 @@ impl App { | BottomWidgetType::Proc | BottomWidgetType::ProcSearch | BottomWidgetType::Disk + | BottomWidgetType::Battery if self.basic_table_widget_state.is_some() => { if let Some(basic_table_widget_state) = diff --git a/src/app/layout_manager.rs b/src/app/layout_manager.rs index 60a241e2..6cd27150 100644 --- a/src/app/layout_manager.rs +++ b/src/app/layout_manager.rs @@ -510,7 +510,141 @@ impl BottomLayout { } } - pub fn init_basic_default() -> Self { + pub fn init_basic_default(use_battery: bool) -> Self { + let table_widgets = if use_battery { + vec![ + BottomCol::builder() + .canvas_handle_width(true) + .children(vec![BottomColRow::builder() + .canvas_handle_height(true) + .children(vec![BottomWidget::builder() + .canvas_handle_width(true) + .widget_type(BottomWidgetType::Disk) + .widget_id(4) + .up_neighbour(Some(100)) + .left_neighbour(Some(8)) + .right_neighbour(Some(DEFAULT_WIDGET_ID)) + .build()]) + .build()]) + .build(), + BottomCol::builder() + .canvas_handle_width(true) + .children(vec![ + BottomColRow::builder() + .canvas_handle_height(true) + .children(vec![BottomWidget::builder() + .canvas_handle_width(true) + .widget_type(BottomWidgetType::Proc) + .widget_id(DEFAULT_WIDGET_ID) + .up_neighbour(Some(100)) + .down_neighbour(Some(DEFAULT_WIDGET_ID + 1)) + .left_neighbour(Some(4)) + .right_neighbour(Some(8)) + .build()]) + .build(), + BottomColRow::builder() + .canvas_handle_height(true) + .children(vec![BottomWidget::builder() + .canvas_handle_width(true) + .widget_type(BottomWidgetType::ProcSearch) + .widget_id(DEFAULT_WIDGET_ID + 1) + .up_neighbour(Some(DEFAULT_WIDGET_ID)) + .left_neighbour(Some(4)) + .right_neighbour(Some(7)) + .build()]) + .build(), + ]) + .build(), + BottomCol::builder() + .canvas_handle_width(true) + .children(vec![BottomColRow::builder() + .canvas_handle_height(true) + .children(vec![BottomWidget::builder() + .canvas_handle_width(true) + .widget_type(BottomWidgetType::Temp) + .widget_id(7) + .up_neighbour(Some(100)) + .left_neighbour(Some(DEFAULT_WIDGET_ID)) + .right_neighbour(Some(8)) + .build()]) + .build()]) + .build(), + BottomCol::builder() + .canvas_handle_width(true) + .children(vec![BottomColRow::builder() + .canvas_handle_height(true) + .children(vec![BottomWidget::builder() + .canvas_handle_width(true) + .widget_type(BottomWidgetType::Battery) + .widget_id(8) + .up_neighbour(Some(100)) + .left_neighbour(Some(7)) + .right_neighbour(Some(4)) + .build()]) + .build()]) + .build(), + ] + } else { + vec![ + BottomCol::builder() + .canvas_handle_width(true) + .children(vec![BottomColRow::builder() + .canvas_handle_height(true) + .children(vec![BottomWidget::builder() + .canvas_handle_width(true) + .widget_type(BottomWidgetType::Disk) + .widget_id(4) + .up_neighbour(Some(100)) + .left_neighbour(Some(7)) + .right_neighbour(Some(DEFAULT_WIDGET_ID)) + .build()]) + .build()]) + .build(), + BottomCol::builder() + .canvas_handle_width(true) + .children(vec![ + BottomColRow::builder() + .canvas_handle_height(true) + .children(vec![BottomWidget::builder() + .canvas_handle_width(true) + .widget_type(BottomWidgetType::Proc) + .widget_id(DEFAULT_WIDGET_ID) + .up_neighbour(Some(100)) + .down_neighbour(Some(DEFAULT_WIDGET_ID + 1)) + .left_neighbour(Some(4)) + .right_neighbour(Some(7)) + .build()]) + .build(), + BottomColRow::builder() + .canvas_handle_height(true) + .children(vec![BottomWidget::builder() + .canvas_handle_width(true) + .widget_type(BottomWidgetType::ProcSearch) + .widget_id(DEFAULT_WIDGET_ID + 1) + .up_neighbour(Some(DEFAULT_WIDGET_ID)) + .left_neighbour(Some(4)) + .right_neighbour(Some(7)) + .build()]) + .build(), + ]) + .build(), + BottomCol::builder() + .canvas_handle_width(true) + .children(vec![BottomColRow::builder() + .canvas_handle_height(true) + .children(vec![BottomWidget::builder() + .canvas_handle_width(true) + .widget_type(BottomWidgetType::Temp) + .widget_id(7) + .up_neighbour(Some(100)) + .left_neighbour(Some(DEFAULT_WIDGET_ID)) + .right_neighbour(Some(4)) + .build()]) + .build()]) + .build(), + ] + }; + BottomLayout { total_row_height_ratio: 3, rows: vec![ @@ -573,119 +707,93 @@ impl BottomLayout { .build(), BottomRow::builder() .canvas_handle_height(true) - .children(vec![ - BottomCol::builder() - .canvas_handle_width(true) - .children(vec![BottomColRow::builder() - .canvas_handle_height(true) - .children(vec![BottomWidget::builder() - .canvas_handle_width(true) - .widget_type(BottomWidgetType::Disk) - .widget_id(4) - .up_neighbour(Some(100)) - .left_neighbour(Some(7)) - .right_neighbour(Some(DEFAULT_WIDGET_ID)) - .build()]) - .build()]) - .build(), - BottomCol::builder() - .canvas_handle_width(true) - .children(vec![ - BottomColRow::builder() - .canvas_handle_height(true) - .children(vec![BottomWidget::builder() - .canvas_handle_width(true) - .widget_type(BottomWidgetType::Proc) - .widget_id(DEFAULT_WIDGET_ID) - .up_neighbour(Some(100)) - .down_neighbour(Some(DEFAULT_WIDGET_ID + 1)) - .left_neighbour(Some(4)) - .right_neighbour(Some(7)) - .build()]) - .build(), - BottomColRow::builder() - .canvas_handle_height(true) - .children(vec![BottomWidget::builder() - .canvas_handle_width(true) - .widget_type(BottomWidgetType::ProcSearch) - .widget_id(DEFAULT_WIDGET_ID + 1) - .up_neighbour(Some(DEFAULT_WIDGET_ID)) - .left_neighbour(Some(4)) - .right_neighbour(Some(7)) - .build()]) - .build(), - ]) - .build(), - BottomCol::builder() - .canvas_handle_width(true) - .children(vec![BottomColRow::builder() - .canvas_handle_height(true) - .children(vec![BottomWidget::builder() - .canvas_handle_width(true) - .widget_type(BottomWidgetType::Temp) - .widget_id(7) - .up_neighbour(Some(100)) - .left_neighbour(Some(DEFAULT_WIDGET_ID)) - .right_neighbour(Some(4)) - .build()]) - .build()]) - .build(), - ]) + .children(table_widgets) .build(), ], } } - pub fn init_default(left_legend: bool) -> Self { + pub fn init_default(left_legend: bool, use_battery: bool) -> Self { + let cpu_layout = if left_legend { + vec![ + BottomWidget::builder() + .width_ratio(3) + .widget_type(BottomWidgetType::CpuLegend) + .widget_id(2) + .down_neighbour(Some(11)) + .right_neighbour(Some(1)) + .canvas_handle_width(true) + .build(), + BottomWidget::builder() + .width_ratio(17) + .widget_type(BottomWidgetType::Cpu) + .widget_id(1) + .down_neighbour(Some(12)) + .left_neighbour(Some(2)) + .right_neighbour(if use_battery { Some(99) } else { None }) + .flex_grow(true) + .build(), + ] + } else { + vec![ + BottomWidget::builder() + .width_ratio(17) + .widget_type(BottomWidgetType::Cpu) + .widget_id(1) + .down_neighbour(Some(11)) + .right_neighbour(Some(2)) + .flex_grow(true) + .build(), + BottomWidget::builder() + .width_ratio(3) + .widget_type(BottomWidgetType::CpuLegend) + .widget_id(2) + .down_neighbour(Some(12)) + .left_neighbour(Some(1)) + .right_neighbour(if use_battery { Some(99) } else { None }) + .canvas_handle_width(true) + .build(), + ] + }; + + let first_row_layout = if use_battery { + vec![ + BottomCol::builder() + .col_width_ratio(2) + .children(vec![BottomColRow::builder() + .total_widget_ratio(20) + .children(cpu_layout) + .build()]) + .build(), + BottomCol::builder() + .col_width_ratio(1) + .children(vec![BottomColRow::builder() + .children(vec![BottomWidget::builder() + .widget_type(BottomWidgetType::Battery) + .widget_id(99) + .down_neighbour(Some(12)) + .left_neighbour(Some(if left_legend { 1 } else { 2 })) + .canvas_handle_width(true) + .build()]) + .build()]) + .build(), + ] + } else { + vec![BottomCol::builder() + .children(vec![BottomColRow::builder() + .total_widget_ratio(20) + .children(cpu_layout) + .build()]) + .build()] + }; + BottomLayout { total_row_height_ratio: 100, rows: vec![ BottomRow::builder() .row_height_ratio(30) - .children(vec![BottomCol::builder() - .children(vec![BottomColRow::builder() - .total_widget_ratio(20) - .children(if left_legend { - vec![ - BottomWidget::builder() - .width_ratio(3) - .widget_type(BottomWidgetType::CpuLegend) - .widget_id(2) - .down_neighbour(Some(11)) - .right_neighbour(Some(1)) - .canvas_handle_width(true) - .build(), - BottomWidget::builder() - .width_ratio(17) - .widget_type(BottomWidgetType::Cpu) - .widget_id(1) - .down_neighbour(Some(12)) - .left_neighbour(Some(2)) - .flex_grow(true) - .build(), - ] - } else { - vec![ - BottomWidget::builder() - .width_ratio(17) - .widget_type(BottomWidgetType::Cpu) - .widget_id(1) - .down_neighbour(Some(11)) - .right_neighbour(Some(2)) - .flex_grow(true) - .build(), - BottomWidget::builder() - .width_ratio(3) - .widget_type(BottomWidgetType::CpuLegend) - .widget_id(2) - .down_neighbour(Some(12)) - .left_neighbour(Some(1)) - .canvas_handle_width(true) - .build(), - ] - }) - .build()]) - .build()]) + .total_col_ratio(if use_battery { 3 } else { 1 }) + .children(first_row_layout) .build(), BottomRow::builder() .total_col_ratio(7) @@ -907,6 +1015,7 @@ impl BottomWidgetType { Proc => "Processes", Temp => "Temperature", Disk => "Disks", + Battery => "Battery", _ => "", } } diff --git a/src/canvas.rs b/src/canvas.rs index a603faa3..9c598567 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -350,6 +350,7 @@ impl Painter { &mut f, app_state, rect[0], + true, app_state.current_widget.widget_id, ), _ => {} @@ -410,6 +411,13 @@ impl Painter { false, widget_id, ), + Battery => self.draw_battery_display( + &mut f, + app_state, + vertical_chunks[4], + false, + widget_id, + ), _ => {} } } @@ -541,9 +549,13 @@ impl Painter { true, widget.widget_id, ), - Battery => { - self.draw_battery_display(f, app_state, *widget_draw_loc, widget.widget_id) - } + Battery => self.draw_battery_display( + f, + app_state, + *widget_draw_loc, + true, + widget.widget_id, + ), _ => {} } } diff --git a/src/canvas/widgets/basic_table_arrows.rs b/src/canvas/widgets/basic_table_arrows.rs index 8284c691..554d7690 100644 --- a/src/canvas/widgets/basic_table_arrows.rs +++ b/src/canvas/widgets/basic_table_arrows.rs @@ -23,19 +23,38 @@ impl BasicTableArrows for Painter { &self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, ) { // Effectively a paragraph with a ton of spacing - let (left_table, right_table) = - if let Some(basic_table_widget_state) = &app_state.basic_table_widget_state { - match basic_table_widget_state.currently_displayed_widget_type { - BottomWidgetType::Proc | BottomWidgetType::ProcSearch => { - (BottomWidgetType::Temp, BottomWidgetType::Disk) - } - BottomWidgetType::Disk => (BottomWidgetType::Proc, BottomWidgetType::Temp), - BottomWidgetType::Temp => (BottomWidgetType::Disk, BottomWidgetType::Proc), - _ => (BottomWidgetType::Disk, BottomWidgetType::Temp), - } - } else { - (BottomWidgetType::Disk, BottomWidgetType::Temp) - }; + let (left_table, right_table) = ( + { + app_state + .current_widget + .left_neighbour + .and_then(|left_widget_id| { + Some( + app_state + .widget_map + .get(&left_widget_id) + .and_then(|left_widget| Some(&left_widget.widget_type)) + .unwrap_or_else(|| &BottomWidgetType::Temp), + ) + }) + .unwrap_or_else(|| &BottomWidgetType::Temp) + }, + { + app_state + .current_widget + .right_neighbour + .and_then(|right_widget_id| { + Some( + app_state + .widget_map + .get(&right_widget_id) + .and_then(|right_widget| Some(&right_widget.widget_type)) + .unwrap_or_else(|| &BottomWidgetType::Disk), + ) + }) + .unwrap_or_else(|| &BottomWidgetType::Disk) + }, + ); let left_name = left_table.get_pretty_name(); let right_name = right_table.get_pretty_name(); @@ -46,12 +65,9 @@ impl BasicTableArrows for Painter { ) as usize; let arrow_text = vec![ - Text::Styled( - format!("\n◄ {}", right_name).into(), - self.colours.text_style, - ), + Text::Styled(format!("\n◄ {}", left_name).into(), self.colours.text_style), Text::Raw(" ".repeat(num_spaces).into()), - Text::Styled(format!("{} ►", left_name).into(), self.colours.text_style), + Text::Styled(format!("{} ►", right_name).into(), self.colours.text_style), ]; let margined_draw_loc = Layout::default() diff --git a/src/canvas/widgets/battery_display.rs b/src/canvas/widgets/battery_display.rs index a31281f4..8d4c7a5f 100644 --- a/src/canvas/widgets/battery_display.rs +++ b/src/canvas/widgets/battery_display.rs @@ -3,6 +3,7 @@ use std::cmp::max; use crate::{ app::App, canvas::{drawing_utils::calculate_basic_use_bars, Painter}, + constants::*, }; use tui::{ @@ -14,17 +15,20 @@ use tui::{ pub trait BatteryDisplayWidget { fn draw_battery_display( - &self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64, + &self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, draw_border: bool, + widget_id: u64, ); } impl BatteryDisplayWidget for Painter { fn draw_battery_display( - &self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64, + &self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, draw_border: bool, + widget_id: u64, ) { if let Some(battery_widget_state) = app_state.battery_state.widget_states.get_mut(&widget_id) { + let is_on_widget = widget_id == app_state.current_widget.widget_id; let title = if app_state.is_expanded { const TITLE_BASE: &str = " Battery ── Esc to go back "; let repeat_num = max( @@ -40,21 +44,29 @@ impl BatteryDisplayWidget for Painter { " Battery ".to_string() }; - let border_and_title_style = if app_state.current_widget.widget_id == widget_id { + let border_and_title_style = if is_on_widget { self.colours.highlighted_border_style } else { self.colours.border_style }; - let battery_block = Block::default() - .title(&title) - .title_style(if app_state.is_expanded { - border_and_title_style - } else { - self.colours.widget_title_style - }) - .borders(Borders::ALL) - .border_style(border_and_title_style); + let battery_block = if draw_border { + Block::default() + .title(&title) + .title_style(if app_state.is_expanded { + border_and_title_style + } else { + self.colours.widget_title_style + }) + .borders(Borders::ALL) + .border_style(border_and_title_style) + } else if is_on_widget { + Block::default() + .borders(*SIDE_BORDERS) + .border_style(self.colours.highlighted_border_style) + } else { + Block::default().borders(Borders::NONE) + }; if let Some(battery_details) = app_state .canvas_data diff --git a/src/canvas/widgets/temp_table.rs b/src/canvas/widgets/temp_table.rs index 1e679904..32b35733 100644 --- a/src/canvas/widgets/temp_table.rs +++ b/src/canvas/widgets/temp_table.rs @@ -94,7 +94,11 @@ impl TempTableWidget for Painter { let temp_block = if draw_border { Block::default() .title(&title) - .title_style(border_and_title_style) + .title_style(if app_state.is_expanded { + border_and_title_style + } else { + self.colours.widget_title_style + }) .borders(Borders::ALL) .border_style(border_and_title_style) } else if is_on_widget { diff --git a/src/options.rs b/src/options.rs index 7351f4c4..d7a32f1f 100644 --- a/src/options.rs +++ b/src/options.rs @@ -262,7 +262,7 @@ pub fn get_widget_layout( let bottom_layout = if get_use_basic_mode(matches, config) { default_widget_id = DEFAULT_WIDGET_ID; - BottomLayout::init_basic_default() + BottomLayout::init_basic_default(get_use_battery(matches, config)) } else if let Some(rows) = &config.row { let mut iter_id = 0; // A lazy way of forcing unique IDs *shrugs* let mut total_height_ratio = 0; @@ -284,7 +284,7 @@ pub fn get_widget_layout( total_row_height_ratio: total_height_ratio, }; - // Confirm that we have at least ONE widget - if we don't, go back to default! + // Confirm that we have at least ONE widget - if not, error out! if iter_id > 0 { ret_bottom_layout.get_movement_mappings(); ret_bottom_layout @@ -295,7 +295,7 @@ pub fn get_widget_layout( } } else { default_widget_id = DEFAULT_WIDGET_ID; - BottomLayout::init_default(left_legend) + BottomLayout::init_default(left_legend, get_use_battery(matches, config)) }; Ok((bottom_layout, default_widget_id)) From 15dba2e6cf390f329b6bbba9686667e240d45633 Mon Sep 17 00:00:00 2001 From: ClementTsang Date: Mon, 27 Apr 2020 16:00:16 -0400 Subject: [PATCH 3/4] bug: fix empty widget in layout --- CHANGELOG.md | 8 +- src/app/layout_manager.rs | 227 ++++++++++++++++++++------------------ 2 files changed, 127 insertions(+), 108 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80f59a6c..eb725d0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,11 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features -- [#58](https://github.com/ClementTsang/bottom/issues/58): I/O stats per process +- [#58](https://github.com/ClementTsang/bottom/issues/58): I/O stats per process. -- [#55](https://github.com/ClementTsang/bottom/issues/55): Battery monitoring widget +- [#55](https://github.com/ClementTsang/bottom/issues/55): Battery monitoring widget. -- [#114](https://github.com/ClementTsang/bottom/pull/114): Process state per process +- [#114](https://github.com/ClementTsang/bottom/pull/114): Process state per process. ### Changes @@ -49,6 +49,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed bug where a single empty row as a layout would crash without a proper warning. The behaviour now errors out with a more helpful message. +- Fixed bug where empty widgets in layout would cause widget movement to not work properly when moving vertically. + ### Development changes - Switch to stateful widget style for tables. diff --git a/src/app/layout_manager.rs b/src/app/layout_manager.rs index 6cd27150..7a7decda 100644 --- a/src/app/layout_manager.rs +++ b/src/app/layout_manager.rs @@ -322,73 +322,81 @@ impl BottomLayout { widget.up_neighbour = Some(current_best_widget_id); } } - } else if let Some(next_row_up) = layout_mapping - .range( + } else { + let mut up_range = layout_mapping.range( ..( row_height_percentage_start, row_height_percentage_start, ), - ) - .next_back() - { - let mut current_best_distance = 0; - let mut current_best_widget_id = widget.widget_id; - let (target_start_width, target_end_width) = - if col_row_children_len > 1 { - ( - col_width_percentage_start - + widget_width_percentage_start - * (col_width_percentage_end - - col_width_percentage_start) - / 100, - col_width_percentage_start - + widget_width_percentage_end - * (col_width_percentage_end - - col_width_percentage_start) - / 100, - ) - } else { - (col_width_percentage_start, col_width_percentage_end) - }; + ); + while let Some(next_row_up) = up_range.next_back() { + let mut current_best_distance = 0; + let mut current_best_widget_id = widget.widget_id; + let (target_start_width, target_end_width) = + if col_row_children_len > 1 { + ( + col_width_percentage_start + + widget_width_percentage_start + * (col_width_percentage_end + - col_width_percentage_start) + / 100, + col_width_percentage_start + + widget_width_percentage_end + * (col_width_percentage_end + - col_width_percentage_start) + / 100, + ) + } else { + ( + col_width_percentage_start, + col_width_percentage_end, + ) + }; - for col_position in &(next_row_up.1).1 { - if let Some(next_col_row) = - (col_position.1).1.iter().next_back() - { - let (candidate_col_start, candidate_col_end) = - ((col_position.0).0, (col_position.0).1); - let candidate_difference = - candidate_col_end - candidate_col_start; - for candidate_widget in &(next_col_row.1).1 { - let candidate_start = candidate_col_start - + (candidate_widget.0).0 * candidate_difference - / 100; - let candidate_end = candidate_col_start - + (candidate_widget.0).1 * candidate_difference - / 100; + for col_position in &(next_row_up.1).1 { + if let Some(next_col_row) = + (col_position.1).1.iter().next_back() + { + let (candidate_col_start, candidate_col_end) = + ((col_position.0).0, (col_position.0).1); + let candidate_difference = + candidate_col_end - candidate_col_start; + for candidate_widget in &(next_col_row.1).1 { + let candidate_start = candidate_col_start + + (candidate_widget.0).0 + * candidate_difference + / 100; + let candidate_end = candidate_col_start + + (candidate_widget.0).1 + * candidate_difference + / 100; - if is_intersecting( - (target_start_width, target_end_width), - (candidate_start, candidate_end), - ) { - let candidate_distance = get_distance( + if is_intersecting( (target_start_width, target_end_width), (candidate_start, candidate_end), - ); + ) { + let candidate_distance = get_distance( + (target_start_width, target_end_width), + (candidate_start, candidate_end), + ); - if current_best_distance < candidate_distance { - current_best_distance = - candidate_distance + 1; - current_best_widget_id = - *(candidate_widget.1); + if current_best_distance + < candidate_distance + { + current_best_distance = + candidate_distance + 1; + current_best_widget_id = + *(candidate_widget.1); + } } } } } - } - if current_best_distance > 0 { - widget.up_neighbour = Some(current_best_widget_id); + if current_best_distance > 0 { + widget.up_neighbour = Some(current_best_widget_id); + break; + } } } @@ -430,72 +438,81 @@ impl BottomLayout { widget.down_neighbour = Some(current_best_widget_id); } } - } else if let Some(next_row_down) = layout_mapping - .range( + } else { + let mut down_range = layout_mapping.range( ( row_height_percentage_start + 1, row_height_percentage_start + 1, ).., - ) - .next() - { - let mut current_best_distance = 0; - let mut current_best_widget_id = widget.widget_id; - let (target_start_width, target_end_width) = - if col_row_children_len > 1 { - ( - col_width_percentage_start - + widget_width_percentage_start - * (col_width_percentage_end - - col_width_percentage_start) - / 100, - col_width_percentage_start - + widget_width_percentage_end - * (col_width_percentage_end - - col_width_percentage_start) - / 100, - ) - } else { - (col_width_percentage_start, col_width_percentage_end) - }; + ); + while let Some(next_row_down) = down_range.next() { + let mut current_best_distance = 0; + let mut current_best_widget_id = widget.widget_id; + let (target_start_width, target_end_width) = + if col_row_children_len > 1 { + ( + col_width_percentage_start + + widget_width_percentage_start + * (col_width_percentage_end + - col_width_percentage_start) + / 100, + col_width_percentage_start + + widget_width_percentage_end + * (col_width_percentage_end + - col_width_percentage_start) + / 100, + ) + } else { + ( + col_width_percentage_start, + col_width_percentage_end, + ) + }; - for col_position in &(next_row_down.1).1 { - if let Some(next_col_row) = (col_position.1).1.iter().next() - { - let (candidate_col_start, candidate_col_end) = - ((col_position.0).0, (col_position.0).1); - let candidate_difference = - candidate_col_end - candidate_col_start; - for candidate_widget in &(next_col_row.1).1 { - let candidate_start = candidate_col_start - + (candidate_widget.0).0 * candidate_difference - / 100; - let candidate_end = candidate_col_start - + (candidate_widget.0).1 * candidate_difference - / 100; + for col_position in &(next_row_down.1).1 { + if let Some(next_col_row) = + (col_position.1).1.iter().next() + { + let (candidate_col_start, candidate_col_end) = + ((col_position.0).0, (col_position.0).1); + let candidate_difference = + candidate_col_end - candidate_col_start; + for candidate_widget in &(next_col_row.1).1 { + let candidate_start = candidate_col_start + + (candidate_widget.0).0 + * candidate_difference + / 100; + let candidate_end = candidate_col_start + + (candidate_widget.0).1 + * candidate_difference + / 100; - if is_intersecting( - (target_start_width, target_end_width), - (candidate_start, candidate_end), - ) { - let candidate_distance = get_distance( + if is_intersecting( (target_start_width, target_end_width), (candidate_start, candidate_end), - ); + ) { + let candidate_distance = get_distance( + (target_start_width, target_end_width), + (candidate_start, candidate_end), + ); - if current_best_distance < candidate_distance { - current_best_distance = - candidate_distance + 1; - current_best_widget_id = - *(candidate_widget.1); + if current_best_distance + < candidate_distance + { + current_best_distance = + candidate_distance + 1; + current_best_widget_id = + *(candidate_widget.1); + } } } } } - } - if current_best_distance > 0 { - widget.down_neighbour = Some(current_best_widget_id); + if current_best_distance > 0 { + widget.down_neighbour = Some(current_best_widget_id); + break; + } } } } From 78e3c37947fa1e8e1746b05888bec5f8dba6fd52 Mon Sep 17 00:00:00 2001 From: ClementTsang Date: Mon, 27 Apr 2020 16:40:45 -0400 Subject: [PATCH 4/4] refactor: fix clippy errors --- src/app/layout_manager.rs | 21 +++++++++--------- src/canvas/widgets/basic_table_arrows.rs | 28 ++++++++++-------------- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/app/layout_manager.rs b/src/app/layout_manager.rs index 7a7decda..739b732b 100644 --- a/src/app/layout_manager.rs +++ b/src/app/layout_manager.rs @@ -323,13 +323,15 @@ impl BottomLayout { } } } else { - let mut up_range = layout_mapping.range( - ..( - row_height_percentage_start, - row_height_percentage_start, - ), - ); - while let Some(next_row_up) = up_range.next_back() { + for next_row_up in layout_mapping + .range( + ..( + row_height_percentage_start, + row_height_percentage_start, + ), + ) + .rev() + { let mut current_best_distance = 0; let mut current_best_widget_id = widget.widget_id; let (target_start_width, target_end_width) = @@ -439,13 +441,12 @@ impl BottomLayout { } } } else { - let mut down_range = layout_mapping.range( + for next_row_down in layout_mapping.range( ( row_height_percentage_start + 1, row_height_percentage_start + 1, ).., - ); - while let Some(next_row_down) = down_range.next() { + ) { let mut current_best_distance = 0; let mut current_best_widget_id = widget.widget_id; let (target_start_width, target_end_width) = diff --git a/src/canvas/widgets/basic_table_arrows.rs b/src/canvas/widgets/basic_table_arrows.rs index 554d7690..6031aa82 100644 --- a/src/canvas/widgets/basic_table_arrows.rs +++ b/src/canvas/widgets/basic_table_arrows.rs @@ -28,14 +28,12 @@ impl BasicTableArrows for Painter { app_state .current_widget .left_neighbour - .and_then(|left_widget_id| { - Some( - app_state - .widget_map - .get(&left_widget_id) - .and_then(|left_widget| Some(&left_widget.widget_type)) - .unwrap_or_else(|| &BottomWidgetType::Temp), - ) + .map(|left_widget_id| { + app_state + .widget_map + .get(&left_widget_id) + .map(|left_widget| &left_widget.widget_type) + .unwrap_or_else(|| &BottomWidgetType::Temp) }) .unwrap_or_else(|| &BottomWidgetType::Temp) }, @@ -43,14 +41,12 @@ impl BasicTableArrows for Painter { app_state .current_widget .right_neighbour - .and_then(|right_widget_id| { - Some( - app_state - .widget_map - .get(&right_widget_id) - .and_then(|right_widget| Some(&right_widget.widget_type)) - .unwrap_or_else(|| &BottomWidgetType::Disk), - ) + .map(|right_widget_id| { + app_state + .widget_map + .get(&right_widget_id) + .map(|right_widget| &right_widget.widget_type) + .unwrap_or_else(|| &BottomWidgetType::Disk) }) .unwrap_or_else(|| &BottomWidgetType::Disk) },