diff options
author | Clement Tsang <34804052+ClementTsang@users.noreply.github.com> | 2020-09-22 18:12:36 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-09-22 18:12:36 -0400 |
commit | 6db76029e2419d53c81cb2111e487f83ee248a2f (patch) | |
tree | 356ff9a92b2d6024d581a6466f832080f2adccbd | |
parent | b0b174eb9843e9af55f5c3f2d37cae96f1744a6b (diff) |
feature: Beginnings of in-app config (#231)
Initial refactorings and additions to support in-app config.
- Refactor our current options logic to support in-app configs. That is, we can write to a config file with our changes now.
- The default action when creating a new config file is to leave it blank. (TBD and for now, not sure on this one)
- Previously, we would set everything in a config file on startup; now we need to read from the config TOML struct whenever.
- `C` keybind is now occupied for configs.
- `no_write` option to never write to a config file.
-rwxr-xr-x | .cargo-husky/hooks/pre-push | 4 | ||||
-rw-r--r-- | .vscode/settings.json | 1 | ||||
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | CONTRIBUTING.md | 2 | ||||
-rw-r--r-- | src/app.rs | 99 | ||||
-rw-r--r-- | src/app/query.rs | 6 | ||||
-rw-r--r-- | src/app/states.rs | 41 | ||||
-rw-r--r-- | src/bin/main.rs | 14 | ||||
-rw-r--r-- | src/canvas.rs | 140 | ||||
-rw-r--r-- | src/canvas/dialogs/help_dialog.rs | 4 | ||||
-rw-r--r-- | src/canvas/screens.rs | 3 | ||||
-rw-r--r-- | src/canvas/screens/config_screen.rs | 57 | ||||
-rw-r--r-- | src/canvas/widgets/battery_display.rs | 2 | ||||
-rw-r--r-- | src/canvas/widgets/mem_graph.rs | 1 | ||||
-rw-r--r-- | src/canvas/widgets/process_table.rs | 6 | ||||
-rw-r--r-- | src/clap.rs | 62 | ||||
-rw-r--r-- | src/constants.rs | 160 | ||||
-rw-r--r-- | src/lib.rs | 175 | ||||
-rw-r--r-- | src/options.rs | 79 | ||||
-rw-r--r-- | src/options/layout_options.rs | 8 |
20 files changed, 472 insertions, 394 deletions
diff --git a/.cargo-husky/hooks/pre-push b/.cargo-husky/hooks/pre-push index 50105aa1..49bed1f2 100755 --- a/.cargo-husky/hooks/pre-push +++ b/.cargo-husky/hooks/pre-push @@ -7,5 +7,5 @@ echo "Running pre-push hook:" echo "Executing: cargo +nightly clippy -- -D clippy::all" cargo +nightly clippy -- -D clippy::all -echo "Executing: cargo test" -cargo test +# echo "Executing: cargo test" +# cargo test diff --git a/.vscode/settings.json b/.vscode/settings.json index 28c61ac4..cd05b700 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -55,6 +55,7 @@ "hjkl", "htop", "indexmap", + "keybinds", "libc", "markdownlint", "memb", diff --git a/CHANGELOG.md b/CHANGELOG.md index 00366b01..6ebdd407 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [#223](https://github.com/ClementTsang/bottom/pull/223): Add tree mode for processes. +- [](): Add in-app configuration. + ### Changes - [#213](https://github.com/ClementTsang/bottom/pull/213), [#214](https://github.com/ClementTsang/bottom/pull/214): Updated help descriptions, added auto-complete generation. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2206f95d..01d3157e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -46,7 +46,7 @@ If you want to help contribute by submitting a PR, by all means, I'm open! In re - You can check clippy using `cargo clippy`. - - I use [cargo-husky](https://github.com/rhysd/cargo-husky) to automatically run a `cargo clippy` and `cargo test` check. + - I use [cargo-husky](https://github.com/rhysd/cargo-husky) to automatically run a `cargo clippy` check. - You may notice that I have fern and log as dependencies; this is mostly for easy debugging via the `debug!()` macro. It writes to the `debug.log` file that will automatically be created if you run in debug mode (so `cargo run`). @@ -1,4 +1,4 @@ -use std::{collections::HashMap, time::Instant}; +use std::{collections::HashMap, io::Write, path::PathBuf, time::Instant}; use unicode_segmentation::GraphemeCursor; use unicode_width::{UnicodeWidthChar, UnicodeWidthStr}; @@ -12,6 +12,7 @@ pub use states::*; use crate::{ canvas, constants, + options::Config, utils::error::{BottomError, Result}, Pid, }; @@ -42,6 +43,7 @@ pub struct AppConfigFields { pub use_old_network_legend: bool, pub table_gap: u16, pub disable_click: bool, + pub no_write: bool, } /// For filtering out information @@ -100,6 +102,9 @@ pub struct App { #[builder(default = false, setter(skip))] pub basic_mode_use_percent: bool, + #[builder(default = false, setter(skip))] + pub is_config_open: bool, + pub cpu_state: CpuState, pub mem_state: MemState, pub net_state: NetState, @@ -113,6 +118,8 @@ pub struct App { pub current_widget: BottomWidget, pub used_widgets: UsedWidgets, pub filters: DataFilters, + pub config: Config, + pub config_path: Option<PathBuf>, } impl App { @@ -171,6 +178,8 @@ impl App { } self.is_force_redraw = true; + } else if self.is_config_open { + self.close_config(); } else { match self.current_widget.widget_type { BottomWidgetType::Proc => { @@ -247,10 +256,14 @@ impl App { self.help_dialog_state.is_showing_help || self.delete_dialog_state.is_showing_dd } + fn ignore_normal_keybinds(&self) -> bool { + self.is_config_open || self.is_in_dialog() + } + pub fn on_tab(&mut self) { - // Disallow usage whilst in a dialog and only in processes + // Allow usage whilst only in processes - if !self.is_in_dialog() { + if !self.ignore_normal_keybinds() { match self.current_widget.widget_type { BottomWidgetType::Cpu => { if let Some(cpu_widget_state) = self @@ -319,7 +332,7 @@ impl App { } pub fn on_slash(&mut self) { - if !self.is_in_dialog() { + if !self.ignore_normal_keybinds() { match &self.current_widget.widget_type { BottomWidgetType::Proc | BottomWidgetType::ProcSort => { // Toggle on @@ -452,6 +465,8 @@ impl App { .search_toggle_ignore_case(); proc_widget_state.update_query(); self.proc_state.force_update = Some(self.current_widget.widget_id - 1); + + // Also toggle it in the config file. } } } @@ -653,7 +668,8 @@ impl App { } pub fn on_up_key(&mut self) { - if !self.is_in_dialog() { + if self.is_config_open { + } else if !self.is_in_dialog() { self.decrement_position_count(); } else if self.help_dialog_state.is_showing_help { self.help_scroll_up(); @@ -662,7 +678,8 @@ impl App { } pub fn on_down_key(&mut self) { - if !self.is_in_dialog() { + if self.is_config_open { + } else if !self.is_in_dialog() { self.increment_position_count(); } else if self.help_dialog_state.is_showing_help { self.help_scroll_down(); @@ -671,7 +688,8 @@ impl App { } pub fn on_left_key(&mut self) { - if !self.is_in_dialog() { + if self.is_config_open { + } else if !self.is_in_dialog() { match self.current_widget.widget_type { BottomWidgetType::Proc => { // if let Some(proc_widget_state) = self @@ -735,7 +753,8 @@ impl App { } pub fn on_right_key(&mut self) { - if !self.is_in_dialog() { + if self.is_config_open { + } else if !self.is_in_dialog() { match self.current_widget.widget_type { BottomWidgetType::Proc => { // if let Some(proc_widget_state) = self @@ -804,7 +823,7 @@ impl App { } pub fn skip_cursor_beginning(&mut self) { - if !self.is_in_dialog() { + if !self.ignore_normal_keybinds() { if let BottomWidgetType::ProcSearch = self.current_widget.widget_type { let is_in_search_widget = self.is_in_search_widget(); if let Some(proc_widget_state) = self @@ -836,11 +855,12 @@ impl App { } } } + } else if self.is_config_open { } } pub fn skip_cursor_end(&mut self) { - if !self.is_in_dialog() { + if !self.ignore_normal_keybinds() { if let BottomWidgetType::ProcSearch = self.current_widget.widget_type { let is_in_search_widget = self.is_in_search_widget(); if let Some(proc_widget_state) = self @@ -882,6 +902,7 @@ impl App { } } } + } else if self.is_config_open { } } @@ -945,7 +966,7 @@ impl App { } // Forbid any char key presses when showing a dialog box... - if !self.is_in_dialog() { + if !self.ignore_normal_keybinds() { let current_key_press_inst = Instant::now(); if current_key_press_inst .duration_since(self.last_key_press) @@ -1034,6 +1055,7 @@ impl App { 'k' | 'l' => self.on_right_key(), _ => {} } + } else if self.is_config_open { } } @@ -1086,6 +1108,9 @@ impl App { self.data_collection.set_frozen_time(); } } + 'C' => { + // self.open_config(), + } 'c' => { if let BottomWidgetType::Proc = self.current_widget.widget_type { if let Some(proc_widget_state) = self @@ -1227,6 +1252,7 @@ impl App { 's' => self.toggle_sort(), 'I' => self.invert_sort(), '%' => self.toggle_percentages(), + ' ' => self.on_space(), _ => {} } @@ -1237,6 +1263,38 @@ impl App { } } + pub fn on_space(&mut self) {} + + pub fn open_config(&mut self) { + self.is_config_open = true; + self.is_force_redraw = true; + } + + pub fn close_config(&mut self) { + self.is_config_open = false; + self.is_force_redraw = true; + } + + /// Call this whenever the config value is updated! + fn update_config_file(&mut self) -> anyhow::Result<()> { + if self.app_config_fields.no_write { + // 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 + std::fs::File::open(config_path)? + .write_all(toml::to_string(&self.config)?.as_bytes())?; + + Ok(()) + } else { + // FIXME: [CONFIG] Put an actual error message? + Err(anyhow::anyhow!( + "Config path was missing, please try restarting bottom..." + )) + } + } + 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 { @@ -1268,7 +1326,8 @@ impl App { } fn expand_widget(&mut self) { - if !self.is_in_dialog() && !self.app_config_fields.use_basic_mode { + // TODO: [BASIC] Expansion in basic mode. + if !self.ignore_normal_keybinds() && !self.app_config_fields.use_basic_mode { // Pop-out mode. We ignore if in process search. match self.current_widget.widget_type { @@ -1300,7 +1359,7 @@ impl App { - Reflection direction. */ - if !self.is_in_dialog() && !self.is_expanded { + if !self.ignore_normal_keybinds() && !self.is_expanded { if let Some(new_widget_id) = &(match direction { WidgetDirection::Left => self.current_widget.left_neighbour, WidgetDirection::Right => self.current_widget.right_neighbour, @@ -1731,7 +1790,7 @@ impl App { } pub fn skip_to_first(&mut self) { - if !self.is_in_dialog() { + if !self.ignore_normal_keybinds() { match self.current_widget.widget_type { BottomWidgetType::Proc => { if let Some(proc_widget_state) = self @@ -1782,13 +1841,14 @@ impl App { _ => {} } self.reset_multi_tap_keys(); - } else { + } 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; } } pub fn skip_to_last(&mut self) { - if !self.is_in_dialog() { + if !self.ignore_normal_keybinds() { match self.current_widget.widget_type { BottomWidgetType::Proc => { if let Some(proc_widget_state) = self @@ -1858,7 +1918,8 @@ impl App { _ => {} } self.reset_multi_tap_keys(); - } else { + } 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 .scroll_state @@ -1868,7 +1929,7 @@ impl App { } pub fn decrement_position_count(&mut self) { - if !self.is_in_dialog() { + if !self.ignore_normal_keybinds() { match self.current_widget.widget_type { BottomWidgetType::Proc => self.increment_process_position(-1), BottomWidgetType::ProcSort => self.increment_process_sort_position(-1), @@ -1881,7 +1942,7 @@ impl App { } pub fn increment_position_count(&mut self) { - if !self.is_in_dialog() { + if !self.ignore_normal_keybinds() { match self.current_widget.widget_type { BottomWidgetType::Proc => self.increment_process_position(1), BottomWidgetType::ProcSort => self.increment_process_sort_position(1), diff --git a/src/app/query.rs b/src/app/query.rs index 488749a4..4d693bb4 100644 --- a/src/app/query.rs +++ b/src/app/query.rs @@ -187,7 +187,11 @@ impl ProcessQuery for ProcWidgetState { let initial_or = Or { lhs: And { lhs: Prefix { - or: Some(Box::new(list_of_ors.pop_front().unwrap())), + or: if let Some(or) = list_of_ors.pop_front() { + Some(Box::new(or)) + } else { + None + }, compare_prefix: None, regex_prefix: None, }, diff --git a/src/app/states.rs b/src/app/states.rs index aaa25004..dea49b18 100644 --- a/src/app/states.rs +++ b/src/app/states.rs @@ -280,6 +280,7 @@ impl Default for ProcColumn { } } +// TODO: [SORTING] Sort by clicking on column header (ie: click on cpu, sort/invert cpu sort)? impl ProcColumn { /// Returns its new status. pub fn toggle(&mut self, column: &ProcessSorting) -> Option<bool> { @@ -303,8 +304,12 @@ impl ProcColumn { self.ordered_columns .iter() .filter_map(|column_type| { - if self.column_mapping.get(&column_type).unwrap().enabled { - Some(1) + if let Some(col_map) = self.column_mapping.get(&column_type) { + if col_map.enabled { + Some(1) + } else { + None + } } else { None } @@ -467,16 +472,20 @@ impl ProcWidgetState { } pub fn toggle_command_and_name(&mut self, is_using_command: bool) { - self.columns + if let Some(pn) = self + .columns .column_mapping .get_mut(&ProcessSorting::ProcessName) - .unwrap() - .enabled = !is_using_command; - self.columns + { + pn.enabled = !is_using_command; + } + if let Some(c) = self + .columns .column_mapping .get_mut(&ProcessSorting::Command) - .unwrap() - .enabled = is_using_command; + { + c.enabled = is_using_command; + } } pub fn get_cursor_position(&self) -> usize { @@ -798,3 +807,19 @@ 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<()>>, +} diff --git a/src/bin/main.rs b/src/bin/main.rs index 83b740f9..37056e78 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -32,7 +32,7 @@ fn main() -> Result<()> { } let matches = clap::get_matches(); - let config_path = read_config(matches.value_of("CONFIG_LOCATION")) + let config_path = read_config(matches.value_of("config_location")) .context("Unable to access the given config file location.")?; let config: Config = create_or_get_config(&config_path) .context("Unable to properly parse or create the config file.")?; @@ -49,6 +49,7 @@ fn main() -> Result<()> { &widget_layout, default_widget_id, &default_widget_type_option, + config_path, )?; // Create painter and set colours. @@ -56,10 +57,8 @@ fn main() -> Result<()> { widget_layout, app.app_config_fields.table_gap, app.app_config_fields.use_basic_mode, - ); - generate_config_colours(&config, &mut painter)?; - painter.colours.generate_remaining_cpu_colours(); - painter.complete_painter_init(); + &config, + )?; // Set up input handling let (sender, receiver) = mpsc::channel(); @@ -80,7 +79,7 @@ fn main() -> Result<()> { // Event loop let (reset_sender, reset_receiver) = mpsc::channel(); - create_event_thread( + create_collection_thread( sender, reset_receiver, &app.app_config_fields, @@ -105,8 +104,7 @@ fn main() -> Result<()> { ctrlc::set_handler(move || { ist_clone.store(true, Ordering::SeqCst); termination_hook(); - }) - .unwrap(); + })?; let mut first_run = true; while !is_terminated.load(Ordering::SeqCst) { diff --git a/src/canvas.rs b/src/canvas.rs index 63e258f4..f4707507 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -1,3 +1,4 @@ +use anyhow::Context; use itertools::izip; use std::collections::HashMap; @@ -10,6 +11,7 @@ use tui::{ use canvas_colours::*; use dialogs::*; +use screens::*; use widgets::*; use crate::{ @@ -20,12 +22,14 @@ use crate::{ }, constants::*, data_conversion::{ConvertedBatteryData, ConvertedCpuData, ConvertedProcessData}, + options::Config, utils::error, }; mod canvas_colours; mod dialogs; mod drawing_utils; +mod screens; mod widgets; /// Point is of time, data @@ -65,13 +69,15 @@ pub struct Painter { col_constraints: Vec<Vec<Constraint>>, col_row_constraints: Vec<Vec<Vec<Constraint>>>, layout_constraints: Vec<Vec<Vec<Vec<Constraint>>>>, - widget_layout: BottomLayout, derived_widget_draw_locs: Vec<Vec<Vec<Vec<Rect>>>>, + widget_layout: BottomLayout, table_height_offset: u16, } impl Painter { - pub fn init(widget_layout: BottomLayout, table_gap: u16, is_basic_mode: bool) -> Self { + pub fn init( + widget_layout: BottomLayout, table_gap: u16, is_basic_mode: bool, config: &Config, + ) -> anyhow::Result<Self> { // Now for modularity; we have to also initialize the base layouts! // We want to do this ONCE and reuse; after this we can just construct // based on the console size. @@ -139,7 +145,7 @@ impl Painter { col_constraints.push(new_col_constraints); }); - Painter { + let mut painter = Painter { colours: CanvasColours::default(), height: 0, width: 0, @@ -152,12 +158,128 @@ impl Painter { widget_layout, derived_widget_draw_locs: Vec::default(), table_height_offset: if is_basic_mode { 2 } else { 4 } + table_gap, + }; + + painter.generate_config_colours(config)?; + painter.colours.generate_remaining_cpu_colours(); + painter.complete_painter_init(); + + Ok(painter) + } + + pub fn generate_config_colours(&mut self, config: &Config) -> anyhow::Result<()> { + if let Some(colours) = &config.colors { + if let Some(border_color) = &colours.border_color { + self.colours + .set_border_colour(border_color) + .context("Update 'border_color' in your config file..")?; + } + + if let Some(highlighted_border_color) = &colours.highlighted_border_color { + self.colours + .set_highlighted_border_colour(highlighted_border_color) + .context("Update 'highlighted_border_color' in your config file..")?; + } + + if let Some(text_color) = &colours.text_color { + self.colours + .set_text_colour(text_color) + .context("Update 'text_color' in your config file..")?; + } + + if let Some(avg_cpu_color) = &colours.avg_cpu_color { + self.colours + .set_avg_cpu_colour(avg_cpu_color) + .context("Update 'avg_cpu_color' in your config file..")?; + } + + if let Some(all_cpu_color) = &colours.all_cpu_color { + self.colours + .set_all_cpu_colour(all_cpu_color) + .context("Update 'all_cpu_color' in your config file..")?; + } + + if let Some(cpu_core_colors) = &colours.cpu_core_colors { + self.colours + .set_cpu_colours(cpu_core_colors) + .context("Update 'cpu_core_colors' in your config file..")?; + } + + if let Some(ram_color) = &colours.ram_color { + self.colours + .set_ram_colour(ram_color) + .context("Update 'ram_color' in your config file..")?; + } + + if let Some(swap_color) = &colours.swap_color { + self.colours + .set_swap_colour(swap_color) + .context("Update 'swap_color' in your config file..")?; + } + + if let Some(rx_color) = &colours.rx_color { + self.colours + .set_rx_colour(rx_color) + .context("Update 'rx_color' in your config file..")?; + } + + if let Some(tx_color) = &colours.tx_color { + self.colours + .set_tx_colour(tx_color) + .context("Update 'tx_color' in your config file..")?; + } + + // if let Some(rx_total_color) = &colours.rx_total_color { + // painter.colours.set_rx_total_colour(rx_total_color)?; + // } + + // if let Some(tx_total_color) = &colours.tx_total_color { + // painter.colours.set_tx_total_colour(tx_total_color)?; + // } + + if let Some(table_header_color) = &colours.table_header_color { + self.colours + .set_table_header_colour(table_header_color) + .context("Update 'table_header_color' in your config file..")?; + } + + if let Some(scroll_entry_text_color) = &colours.selected_text_color { + self.colours + .set_scroll_entry_text_color(scroll_entry_text_color) + .context("Update 'selected_text_color' in your config file..")?; + } + + if let Some(scroll_entry_bg_color) = &colours.selected_bg_color { + self.colours + .set_scroll_entry_bg_color(scroll_entry_bg_color) + .context("Update 'selected_bg_color' in your config file..")?; + } + + if let Some(widget_title_color) = &colours.widget_title_color { + self.colours + .set_widget_title_colour(widget_title_color) + .context("Update 'widget_title_color' in your config file..")?; + } + + if let Some(graph_color) = &colours.graph_color { + self.colours + .set_graph_colour(graph_color) + .context("Update 'graph_color' in your config file..")?; + } + + if let Some(battery_colors) = &colours.battery_colors { + self.colours + .set_battery_colors(battery_colors) + .context("Update 'battery_colors' in your config file.")?; + } } + + Ok(()) } /// Must be run once before drawing, but after setting colours. /// This is to set some remaining styles and text. - pub fn complete_painter_init(&mut self) { + fn complete_painter_init(&mut self) { self.is_mac_os = cfg!(target_os = "macos"); let mut styled_help_spans = Vec::new(); @@ -191,6 +313,9 @@ impl Painter { self.styled_help_text = styled_help_spans; } + // FIXME: [CONFIG] write this, should call painter init and any changed colour functions... + pub fn update_painter_colours(&mut self) {} + pub fn draw_data<B: Backend>( &mut self, terminal: &mut Terminal<B>, app_state: &mut app::App, ) -> error::Result<()> { @@ -406,6 +531,13 @@ impl Painter { ), _ => {} } + } else if app_state.is_config_open { + let rect = Layout::default() + .margin(0) + .constraints([Constraint::Percentage(100)].as_ref()) + .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. diff --git a/src/canvas/dialogs/help_dialog.rs b/src/canvas/dialogs/help_dialog.rs index 2b148f16..fe0f1c52 100644 --- a/src/canvas/dialogs/help_dialog.rs +++ b/src/canvas/dialogs/help_dialog.rs @@ -1,5 +1,6 @@ use unicode_width::UnicodeWidthStr; +use crate::{app::App, canvas::Painter, constants}; use tui::{ backend::Backend, layout::{Alignment, Rect}, @@ -7,8 +8,6 @@ use tui::{ widgets::{Block, Borders, Paragraph}, }; -use crate::{app::App, canvas::Painter, constants}; - const HELP_BASE: &str = " Help ── Esc to close "; pub trait HelpDialog { @@ -17,6 +16,7 @@ pub trait HelpDialog { ); } +// 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, diff --git a/src/canvas/screens.rs b/src/canvas/screens.rs new file mode 100644 index 00000000..e17aa573 --- /dev/null +++ b/src/canvas/screens.rs @@ -0,0 +1,3 @@ +pub mod config_screen; + +pub use config_screen::*; diff --git a/src/canvas/screens/config_screen.rs b/src/canvas/screens/config_screen.rs new file mode 100644 index 00000000..6aa22493 --- /dev/null +++ b/src/canvas/screens/config_screen.rs @@ -0,0 +1,57 @@ +use crate::{app::App, canvas::Painter, constants}; +use tui::{ + backend::Backend, + layout::Constraint, + layout::Direction, + layout::Layout, + layout::{Alignment, Rect}, + terminal::Frame, + 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(&" Config ") + .title_style(self.colours.border_style) + .style(self.colours.border_style) + .borders(Borders::ALL) + .border_style(self.colours.border_style); + + f.render_widget(config_block, draw_loc); + + // let margined_draw_locs = Layout::default() + // .margin(2) + // .direction(Direction::Horizontal) + // .constraints( + // [ + // Constraint::Percentage(33), + // Constraint::Percentage(34), + // Constraint::Percentage(33), + // ] + // .as_ref(), + // ) + // .split(draw_loc) + // .into_iter() + // .map(|loc| { + // // Required to properly margin in *between* the rectangles. + // Layout::default() + // .horizontal_margin(1) + // .constraints([Constraint::Percentage(100)].as_ref()) + // .split(loc)[0] + // }) + // .collect::<Vec<Rect>>(); + + // for dl in margined_draw_locs { + // f.render_widget(Block::default().borders(Borders::ALL), dl); + // } + } +} diff --git a/src/canvas/widgets/battery_display.rs b/src/canvas/widgets/battery_display.rs index 3e4ca3e9..e50ed515 100644 --- a/src/canvas/widgets/battery_display.rs +++ b/src/canvas/widgets/battery_display.rs @@ -223,7 +223,7 @@ impl BatteryDisplayWidget for Painter { .block(Block::default()) .divider(tui::symbols::line::VERTICAL) .style(self.colours.text_style) - .highlight_style(self.colours.currently_selected_text_style) + .highlight_style(self.colours.currently_selected_text_style) //FIXME: [HIGHLIGHT] THIS IS BROKEN ON TUI's SIDE, override this with your own style... .select(battery_widget_state.currently_selected_battery_index), tab_draw_loc, ); diff --git a/src/canvas/widgets/mem_graph.rs |