summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClement Tsang <34804052+ClementTsang@users.noreply.github.com>2020-09-22 18:12:36 -0400
committerGitHub <noreply@github.com>2020-09-22 18:12:36 -0400
commit6db76029e2419d53c81cb2111e487f83ee248a2f (patch)
tree356ff9a92b2d6024d581a6466f832080f2adccbd
parentb0b174eb9843e9af55f5c3f2d37cae96f1744a6b (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-push4
-rw-r--r--.vscode/settings.json1
-rw-r--r--CHANGELOG.md2
-rw-r--r--CONTRIBUTING.md2
-rw-r--r--src/app.rs99
-rw-r--r--src/app/query.rs6
-rw-r--r--src/app/states.rs41
-rw-r--r--src/bin/main.rs14
-rw-r--r--src/canvas.rs140
-rw-r--r--src/canvas/dialogs/help_dialog.rs4
-rw-r--r--src/canvas/screens.rs3
-rw-r--r--src/canvas/screens/config_screen.rs57
-rw-r--r--src/canvas/widgets/battery_display.rs2
-rw-r--r--src/canvas/widgets/mem_graph.rs1
-rw-r--r--src/canvas/widgets/process_table.rs6
-rw-r--r--src/clap.rs62
-rw-r--r--src/constants.rs160
-rw-r--r--src/lib.rs175
-rw-r--r--src/options.rs79
-rw-r--r--src/options/layout_options.rs8
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`).
diff --git a/src/app.rs b/src/app.rs
index 759cfd47..33c11ebd 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -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