From 8cb217cd198e2de84b054682e58c22505fe94287 Mon Sep 17 00:00:00 2001 From: dastarruer Date: Sat, 11 Apr 2026 03:59:25 -0400 Subject: [PATCH] feature: add a global `bg_color` option for widgets (#1979) * feature: add global bg_color option * period * fmt * oops, format again * update default config + schema * rename field + apply it to dialogs * update dialog to just draw once * handle basic * add test + some small tweaks --------- Co-authored-by: Clement Tsang <34804052+ClementTsang@users.noreply.github.com> --- CHANGELOG.md | 1 + .../configuration/config-file/styling.md | 1 + sample_configs/default_config.toml | 3 +- sample_configs/demo_config.toml | 1 + schema/nightly/bottom.json | 11 ++++ src/canvas.rs | 8 +++ src/canvas/components/data_table/draw.rs | 17 ++++-- src/canvas/components/data_table/styling.rs | 2 + src/canvas/components/time_graph/base.rs | 16 ++++-- .../components/time_graph/variants/percent.rs | 4 +- src/canvas/components/widget_carousel.rs | 4 ++ src/canvas/dialogs/help_dialog.rs | 3 +- src/canvas/dialogs/process_kill_dialog.rs | 12 ++--- src/canvas/drawing_utils.rs | 24 +++++---- src/canvas/widgets/battery_display.rs | 1 + src/canvas/widgets/cpu_basic.rs | 17 +++--- src/canvas/widgets/mem_basic.rs | 17 +++--- src/canvas/widgets/network_basic.rs | 17 +++--- src/canvas/widgets/network_graph.rs | 26 ++++++---- src/canvas/widgets/process_table.rs | 9 +++- src/constants.rs | 3 +- src/options/config/style.rs | 6 ++- src/options/config/style/themes/default.rs | 1 + src/options/config/style/themes/gruvbox.rs | 4 +- src/options/config/style/themes/nord.rs | 4 +- src/options/config/style/utils.rs | 52 ++++++++++++++++++- src/options/config/style/widgets.rs | 3 ++ 27 files changed, 200 insertions(+), 67 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e071ba1..bd3b688b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ That said, these are more guidelines rather than hard rules, though the project - [#1938](https://github.com/ClementTsang/bottom/pull/1938), [#1980](https://github.com/ClementTsang/bottom/pull/1980): Report average packet size and packet rate. - [#2003](https://github.com/ClementTsang/bottom/pull/2003): Configurable default sort column for temperature and disk table widgets. +- [#1979](https://github.com/ClementTsang/bottom/pull/1979): Add global `bg_color` option to set widget background colour. ### Other diff --git a/docs/content/configuration/config-file/styling.md b/docs/content/configuration/config-file/styling.md index cd6e9c55..1aa8181a 100644 --- a/docs/content/configuration/config-file/styling.md +++ b/docs/content/configuration/config-file/styling.md @@ -162,6 +162,7 @@ These can be set under `[styles.widgets]`: | `border_color` | The colour of the widgets' borders | `border_color = "white"` | | `selected_border_color` | The colour of a widget's borders when the widget is selected | `selected_border_color = "white"` | | `widget_title` | Text styling for a widget's title | `widget_title = { color = "black", bg_color = "blue", bold = true }` | +| `bg_color` | The background color of the widgets. | `bg_color = "black"` | | `text` | Text styling for text in general | `text = { color = "black", bg_color = "blue", bold = true }` | | `selected_text` | Text styling for text when representing something that is selected | `selected_text = { color = "black", bg_color = "blue", bold = true }` | | `disabled_text` | Text styling for text when representing something that is disabled | `disabled_text = { color = "black", bg_color = "blue", bold = true }` | diff --git a/sample_configs/default_config.toml b/sample_configs/default_config.toml index 44286645..1601f1d3 100644 --- a/sample_configs/default_config.toml +++ b/sample_configs/default_config.toml @@ -295,7 +295,8 @@ #text = {color = "gray"} #selected_text = {color = "black", bg_color = "light blue"} #disabled_text = {color = "dark gray"} - +# Disabled by default +#bg_color = "black" # Only on Linux #thread_text = {color = "green"} diff --git a/sample_configs/demo_config.toml b/sample_configs/demo_config.toml index dde4d0b5..dd5ab1b9 100644 --- a/sample_configs/demo_config.toml +++ b/sample_configs/demo_config.toml @@ -19,3 +19,4 @@ theme = "gruvbox" [processes] columns = ["PID", "Name", "CPU%", "Mem%", "Rps", "Wps", "TRead", "TWrite", "State", "Time", "Virt"] + diff --git a/schema/nightly/bottom.json b/schema/nightly/bottom.json index 8ba11c7c..8dc85c51 100644 --- a/schema/nightly/bottom.json +++ b/schema/nightly/bottom.json @@ -1113,6 +1113,17 @@ "description": "General styling for generic widgets.", "type": "object", "properties": { + "bg_color": { + "description": "Background color for widgets.", + "anyOf": [ + { + "$ref": "#/$defs/ColorStr" + }, + { + "type": "null" + } + ] + }, "border_color": { "description": "The colour of the widgets' borders.", "anyOf": [ diff --git a/src/canvas.rs b/src/canvas.rs index 62964b8e..3846097e 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -120,6 +120,10 @@ impl Painter { // TODO: Make drawing dialog generic. if app_state.help_dialog_state.is_showing_help { + let area = f.area(); + f.buffer_mut() + .set_style(area, self.styles.general_widget_style); + let gen_help_len = GENERAL_HELP_TEXT.len() as u16 + 3; let border_len = terminal_height.saturating_sub(gen_help_len) / 2; let [_, vertical_dialog_chunk, _] = Layout::default() @@ -178,6 +182,10 @@ impl Painter { self.draw_help_dialog(f, app_state, middle_dialog_chunk); } else if app_state.process_kill_dialog.is_open() { + let area = f.area(); + f.buffer_mut() + .set_style(area, self.styles.general_widget_style); + // FIXME: For width, just limit to a max size or full width. For height, not sure. Maybe pass max and let child handle? let horizontal_padding = if terminal_width < 100 { 0 } else { 5 }; let vertical_padding = if terminal_height < 100 { 0 } else { 5 }; diff --git a/src/canvas/components/data_table/draw.rs b/src/canvas/components/data_table/draw.rs index 2cbd9384..009b9d5f 100644 --- a/src/canvas/components/data_table/draw.rs +++ b/src/canvas/components/data_table/draw.rs @@ -8,7 +8,7 @@ use tui::{ Frame, layout::{Constraint, Direction, Layout, Rect}, text::{Line, Span, Text}, - widgets::{Block, Cell, Row, Table}, + widgets::{Block, Cell, Padding, Row, Table}, }; use super::{ @@ -77,8 +77,13 @@ where self.styling.border_style }; - let mut block = widget_block(self.props.is_basic, is_selected, self.styling.border_type) - .border_style(border_style); + let mut block = widget_block( + self.props.is_basic, + is_selected, + self.styling.border_type, + self.styling.general_widget_style, + ) + .border_style(border_style); if let Some((left_title, right_title)) = self.generate_title(draw_info, data_len) { if !self.props.is_basic { @@ -135,11 +140,13 @@ where let draw_loc = draw_info.loc; let margined_draw_loc = Layout::default() .constraints([Constraint::Percentage(100)]) - .horizontal_margin(u16::from(self.props.is_basic && !draw_info.is_on_widget())) .direction(Direction::Horizontal) .split(draw_loc)[0]; - let block = self.block(draw_info, self.data.len()); + let mut block = self.block(draw_info, self.data.len()); + if self.props.is_basic && !draw_info.is_on_widget() { + block = block.padding(Padding::horizontal(1)) + } let (inner_width, inner_height) = { let inner_rect = block.inner(margined_draw_loc); diff --git a/src/canvas/components/data_table/styling.rs b/src/canvas/components/data_table/styling.rs index 1fd63a02..df21d808 100644 --- a/src/canvas/components/data_table/styling.rs +++ b/src/canvas/components/data_table/styling.rs @@ -11,6 +11,7 @@ pub struct DataTableStyling { pub text_style: Style, pub highlighted_text_style: Style, pub title_style: Style, + pub general_widget_style: Style, } impl DataTableStyling { @@ -23,6 +24,7 @@ impl DataTableStyling { text_style: styles.text_style, highlighted_text_style: styles.selected_text_style, title_style: styles.widget_title_style, + general_widget_style: styles.general_widget_style, } } } diff --git a/src/canvas/components/time_graph/base.rs b/src/canvas/components/time_graph/base.rs index a599c98b..dea8dcf1 100644 --- a/src/canvas/components/time_graph/base.rs +++ b/src/canvas/components/time_graph/base.rs @@ -64,6 +64,9 @@ pub struct TimeGraph<'a> { /// The graph style. pub graph_style: Style, + /// The background color + pub general_widget_style: Style, + /// The border style. pub border_style: Style, @@ -150,9 +153,14 @@ impl TimeGraph<'_> { let data = graph_data.into_iter().map(create_dataset).collect(); let block = { - let mut b = widget_block(false, self.is_selected, self.border_type) - .border_style(self.border_style) - .title_top(Line::styled(self.title.as_ref(), self.title_style)); + let mut b = widget_block( + false, + self.is_selected, + self.border_type, + self.general_widget_style, + ) + .border_style(self.border_style) + .title_top(Line::styled(self.title.as_ref(), self.title_style)); if self.is_expanded { b = b.title_top(Line::styled(" Esc to go back ", self.title_style).right_aligned()) @@ -167,6 +175,7 @@ impl TimeGraph<'_> { .x_axis(x_axis) .y_axis(y_axis) .marker(self.marker) + .style(self.general_widget_style) .legend_style(self.graph_style) .legend_position(self.legend_position) .hidden_legend_constraints( @@ -232,6 +241,7 @@ mod test { y_bounds: AxisBound::Max(100.5), y_labels: &Y_LABELS, graph_style: Style::default().fg(Color::Red), + general_widget_style: Style::default().bg(Color::Black), border_style: Style::default().fg(Color::Blue), border_type: BorderType::Plain, is_selected: false, diff --git a/src/canvas/components/time_graph/variants/percent.rs b/src/canvas/components/time_graph/variants/percent.rs index 9382a2d8..3e7bac78 100644 --- a/src/canvas/components/time_graph/variants/percent.rs +++ b/src/canvas/components/time_graph/variants/percent.rs @@ -35,7 +35,7 @@ pub(crate) struct PercentTimeGraph<'a> { pub(crate) current_widget: u64, /// Whether the current widget is expanded. - /// + /// /// This is mostly used as a shared mutability workaround due to [`App`] /// being a giant state struct. pub(crate) is_expanded: bool, @@ -71,6 +71,7 @@ impl<'a> PercentTimeGraph<'a> { }; let graph_style = self.styles.graph_style; + let general_widget_style = self.styles.general_widget_style; let border_style = get_border_style(self.styles, self.widget_id, self.current_widget); let title_style = self.styles.widget_title_style; let border_type = self.styles.border_type; @@ -81,6 +82,7 @@ impl<'a> PercentTimeGraph<'a> { y_bounds: Y_BOUNDS, y_labels: &Y_LABELS, graph_style, + general_widget_style, border_style, border_type, title: self.title, diff --git a/src/canvas/components/widget_carousel.rs b/src/canvas/components/widget_carousel.rs index 73590dff..51cf464d 100644 --- a/src/canvas/components/widget_carousel.rs +++ b/src/canvas/components/widget_carousel.rs @@ -115,6 +115,10 @@ impl Painter { .horizontal_margin(1) .split(draw_loc); + // Done like this for now since it's easier to just manually paint instead of dealing with blocks. + f.buffer_mut() + .set_style(draw_loc, self.styles.general_widget_style); + f.render_widget( Paragraph::new(left_arrow_text).block(Block::default()), margined_draw_loc[0], diff --git a/src/canvas/dialogs/help_dialog.rs b/src/canvas/dialogs/help_dialog.rs index 6f2aad85..a4e9aec9 100644 --- a/src/canvas/dialogs/help_dialog.rs +++ b/src/canvas/dialogs/help_dialog.rs @@ -41,8 +41,7 @@ impl Painter { pub fn draw_help_dialog(&self, f: &mut Frame<'_>, app_state: &mut App, draw_loc: Rect) { let styled_help_text = self.help_text_lines(); - let block = dialog_block(self.styles.border_type) - .border_style(self.styles.border_style) + let block = dialog_block(self.styles.border_type, self.styles.border_style) .title_top(Line::styled(" Help ", self.styles.widget_title_style)) .title_top( Line::styled(" Esc to close ", self.styles.widget_title_style).right_aligned(), diff --git a/src/canvas/dialogs/process_kill_dialog.rs b/src/canvas/dialogs/process_kill_dialog.rs index 2e1fb7c6..e60ff3ba 100644 --- a/src/canvas/dialogs/process_kill_dialog.rs +++ b/src/canvas/dialogs/process_kill_dialog.rs @@ -677,11 +677,9 @@ impl ProcessKillDialog { } }; - let block = dialog_block(styles.border_type) + let block = dialog_block(styles.border_type, styles.border_style) .title_top(title) - .title_top(Line::styled(" Esc to close ", styles.widget_title_style).right_aligned()) - .style(styles.border_style) - .border_style(styles.border_style); + .title_top(Line::styled(" Esc to close ", styles.widget_title_style).right_aligned()); let num_lines = text.line_count(block.inner(draw_area).width) as u16; @@ -811,11 +809,9 @@ impl ProcessKillDialog { .alignment(Alignment::Center) .wrap(Wrap { trim: true }); - let block = dialog_block(styles.border_type) + let block = dialog_block(styles.border_type, styles.border_style) .title_top(title) - .title_top(Line::styled(" Esc to close ", styles.widget_title_style).right_aligned()) - .style(styles.border_style) - .border_style(styles.border_style); + .title_top(Line::styled(" Esc to close ", styles.widget_title_style).right_aligned()); let num_lines = text.line_count(block.inner(draw_area).width) as u16; diff --git a/src/canvas/drawing_utils.rs b/src/canvas/drawing_utils.rs index ff7ccd23..1e971551 100644 --- a/src/canvas/drawing_utils.rs +++ b/src/canvas/drawing_utils.rs @@ -2,6 +2,7 @@ use std::time::Instant; use tui::{ layout::Rect, + style::Style, widgets::{Block, BorderType, Borders}, }; @@ -29,26 +30,31 @@ pub fn should_hide_x_label( } /// Return a widget block. -pub fn widget_block(is_basic: bool, is_selected: bool, border_type: BorderType) -> Block<'static> { - let mut block = Block::default().border_type(border_type); - +pub fn widget_block( + is_basic: bool, is_selected: bool, border_type: BorderType, widget_style: Style, +) -> Block<'static> { if is_basic { if is_selected { - block = block.borders(SIDE_BORDERS); + Block::default() + .border_type(border_type) + .style(widget_style) + .borders(SIDE_BORDERS) } else { - block = block.borders(Borders::empty()); + Block::default().style(widget_style) } } else { - block = block.borders(Borders::all()); + Block::default() + .border_type(border_type) + .style(widget_style) + .borders(Borders::all()) } - - block } /// Return a dialog block. -pub fn dialog_block(border_type: BorderType) -> Block<'static> { +pub fn dialog_block(border_type: BorderType, border_style: Style) -> Block<'static> { Block::default() .border_type(border_type) + .border_style(border_style) .borders(Borders::all()) } diff --git a/src/canvas/widgets/battery_display.rs b/src/canvas/widgets/battery_display.rs index f0b42b24..9e4154f3 100644 --- a/src/canvas/widgets/battery_display.rs +++ b/src/canvas/widgets/battery_display.rs @@ -51,6 +51,7 @@ impl Painter { app_state.app_config_fields.use_basic_mode, is_selected, self.styles.border_type, + self.styles.general_widget_style, ) .border_style(border_style) .title_top(Line::styled(" Battery ", self.styles.widget_title_style)); diff --git a/src/canvas/widgets/cpu_basic.rs b/src/canvas/widgets/cpu_basic.rs index 8d2a9bda..19273cd7 100644 --- a/src/canvas/widgets/cpu_basic.rs +++ b/src/canvas/widgets/cpu_basic.rs @@ -33,13 +33,16 @@ impl Painter { // If not, then add a new column. Then, from this, split the row space across ALL columns. // From there, generate the desired lengths. - if app_state.current_widget.widget_id == widget_id { - f.render_widget( - widget_block(true, true, self.styles.border_type) - .border_style(self.styles.highlighted_border_style), - draw_loc, - ); - } + f.render_widget( + widget_block( + true, + app_state.current_widget.widget_id == widget_id, + self.styles.border_type, + self.styles.general_widget_style, + ) + .border_style(self.styles.highlighted_border_style), + draw_loc, + ); // TODO: This is pretty ugly. Is there a better way of doing it? let mut avg_index = cpu_data.len() + 1; diff --git a/src/canvas/widgets/mem_basic.rs b/src/canvas/widgets/mem_basic.rs index a2f66d44..45ae41ff 100644 --- a/src/canvas/widgets/mem_basic.rs +++ b/src/canvas/widgets/mem_basic.rs @@ -46,13 +46,16 @@ impl Painter { ) { let mut draw_widgets: Vec> = Vec::new(); - if app_state.current_widget.widget_id == widget_id { - f.render_widget( - widget_block(true, true, self.styles.border_type) - .border_style(self.styles.highlighted_border_style), - draw_loc, - ); - } + f.render_widget( + widget_block( + true, + app_state.current_widget.widget_id == widget_id, + self.styles.border_type, + self.styles.general_widget_style, + ) + .border_style(self.styles.highlighted_border_style), + draw_loc, + ); let data = app_state.data_store.get_data(); diff --git a/src/canvas/widgets/network_basic.rs b/src/canvas/widgets/network_basic.rs index b9ca4849..454e50d3 100644 --- a/src/canvas/widgets/network_basic.rs +++ b/src/canvas/widgets/network_basic.rs @@ -21,13 +21,16 @@ impl Painter { ) { let show_packets = app_state.app_config_fields.network_show_packets; - if app_state.current_widget.widget_id == widget_id { - f.render_widget( - widget_block(true, true, self.styles.border_type) - .border_style(self.styles.highlighted_border_style), - draw_loc, - ); - } + f.render_widget( + widget_block( + true, + app_state.current_widget.widget_id == widget_id, + self.styles.border_type, + self.styles.general_widget_style, + ) + .border_style(self.styles.highlighted_border_style), + draw_loc, + ); let use_binary_prefix = app_state.app_config_fields.network_use_binary_prefix; let network_data = &(app_state.data_store.get_data().network_harvest); diff --git a/src/canvas/widgets/network_graph.rs b/src/canvas/widgets/network_graph.rs index 875400c5..63fcb75e 100644 --- a/src/canvas/widgets/network_graph.rs +++ b/src/canvas/widgets/network_graph.rs @@ -5,7 +5,7 @@ use tui::{ layout::{Constraint, Direction, Layout, Rect}, symbols::Marker, text::Text, - widgets::{Block, Borders, Row, Table}, + widgets::{Row, Table}, }; use crate::{ @@ -13,7 +13,7 @@ use crate::{ canvas::{ Painter, components::time_graph::{AxisBound, ChartScaling, GraphData, TimeGraph}, - drawing_utils::should_hide_x_label, + drawing_utils::{should_hide_x_label, widget_block}, widgets::{PacketInfo, calculate_packet_info}, }, utils::{ @@ -267,6 +267,7 @@ impl Painter { y_bounds, y_labels: &(y_labels.into_iter().map(Into::into).collect::>()), graph_style: self.styles.graph_style, + general_widget_style: self.styles.general_widget_style, border_style, border_type: self.styles.border_type, title: " Network ".into(), @@ -348,6 +349,19 @@ impl Painter { let column_width = draw_loc.width.saturating_sub(2) / num_columns as u16; // Draw + let current_border_style = if app_state.current_widget.widget_id == widget_id { + self.styles.highlighted_border_style + } else { + self.styles.border_style + }; + let block = widget_block( + app_state.app_config_fields.use_basic_mode, + app_state.current_widget.widget_id == widget_id, + self.styles.border_type, + self.styles.general_widget_style, + ) + .border_style(current_border_style); + f.render_widget( Table::new( total_network, @@ -356,13 +370,7 @@ impl Painter { .collect::>()), ) .header(Row::new(headers).style(self.styles.table_header_style)) - .block(Block::default().borders(Borders::ALL).border_style( - if app_state.current_widget.widget_id == widget_id { - self.styles.highlighted_border_style - } else { - self.styles.border_style - }, - )) + .block(block) .style(self.styles.text_style), draw_loc, ); diff --git a/src/canvas/widgets/process_table.rs b/src/canvas/widgets/process_table.rs index 2652ea06..352e9256 100644 --- a/src/canvas/widgets/process_table.rs +++ b/src/canvas/widgets/process_table.rs @@ -254,8 +254,13 @@ impl Painter { }; let process_search_block = { - let mut block = widget_block(is_basic, is_selected, self.styles.border_type) - .border_style(current_border_style); + let mut block = widget_block( + is_basic, + is_selected, + self.styles.border_type, + self.styles.general_widget_style, + ) + .border_style(current_border_style); if !is_basic { block = block.title_top( diff --git a/src/constants.rs b/src/constants.rs index ba69a0a3..89bba358 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -541,7 +541,8 @@ pub(crate) const CONFIG_TEXT: &str = r#"# This is a default config file for bott #text = {color = "gray"} #selected_text = {color = "black", bg_color = "light blue"} #disabled_text = {color = "dark gray"} - +# Disabled by default +#bg_color = "black" # Only on Linux #thread_text = {color = "green"} diff --git a/src/options/config/style.rs b/src/options/config/style.rs index cc569c95..5e3c0773 100644 --- a/src/options/config/style.rs +++ b/src/options/config/style.rs @@ -25,7 +25,9 @@ use utils::{opt, set_colour, set_colour_list, set_style}; use widgets::WidgetStyle; use super::Config; -use crate::options::{OptionError, OptionResult, args::BottomArgs}; +use crate::options::{ + OptionError, OptionResult, args::BottomArgs, config::style::utils::set_bg_colour, +}; #[derive(Clone, Debug, Deserialize, Serialize)] #[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))] @@ -117,6 +119,7 @@ pub struct Styles { pub(crate) selected_text_style: Style, pub(crate) table_header_style: Style, pub(crate) widget_title_style: Style, + pub(crate) general_widget_style: Style, pub(crate) graph_style: Style, pub(crate) graph_legend_style: Style, pub(crate) high_battery: Style, @@ -207,6 +210,7 @@ impl Styles { set_style!(self.graph_legend_style, config.graphs, legend_text); // General widget text. + set_bg_colour!(self.general_widget_style, config.widgets, bg_color); set_style!(self.widget_title_style, config.widgets, widget_title); set_style!(self.text_style, config.widgets, text); set_style!(self.selected_text_style, config.widgets, selected_text); diff --git a/src/options/config/style/themes/default.rs b/src/options/config/style/themes/default.rs index 8d3e9cde..64b7bf1d 100644 --- a/src/options/config/style/themes/default.rs +++ b/src/options/config/style/themes/default.rs @@ -59,6 +59,7 @@ impl Styles { selected_text_style: DEFAULT_SELECTED_TEXT_STYLE, table_header_style: color!(HIGHLIGHT_COLOUR).add_modifier(Modifier::BOLD), widget_title_style: color!(TEXT_COLOUR), + general_widget_style: Style::default(), graph_style: color!(TEXT_COLOUR), graph_legend_style: color!(TEXT_COLOUR), high_battery: color!(Color::Green), diff --git a/src/options/config/style/themes/gruvbox.rs b/src/options/config/style/themes/gruvbox.rs index c415be16..807cdfd5 100644 --- a/src/options/config/style/themes/gruvbox.rs +++ b/src/options/config/style/themes/gruvbox.rs @@ -1,5 +1,5 @@ use tui::{ - style::{Color, Modifier}, + style::{Color, Modifier, Style}, widgets::BorderType, }; @@ -58,6 +58,7 @@ impl Styles { text_style: hex!("#ebdbb2"), selected_text_style: hex!("#1d2021").bg(hex_colour!("#ebdbb2")), table_header_style: hex!("#83a598").add_modifier(Modifier::BOLD), + general_widget_style: Style::default(), widget_title_style: hex!("#ebdbb2"), graph_style: hex!("#ebdbb2"), graph_legend_style: hex!("#ebdbb2"), @@ -123,6 +124,7 @@ impl Styles { text_style: hex!("#3c3836"), selected_text_style: hex!("#ebdbb2").bg(hex_colour!("#3c3836")), table_header_style: hex!("#076678").add_modifier(Modifier::BOLD), + general_widget_style: Style::default(), widget_title_style: hex!("#3c3836"), graph_style: hex!("#3c3836"), graph_legend_style: hex!("#3c3836"), diff --git a/src/options/config/style/themes/nord.rs b/src/options/config/style/themes/nord.rs index 2e46d5c4..50c7a653 100644 --- a/src/options/config/style/themes/nord.rs +++ b/src/options/config/style/themes/nord.rs @@ -1,5 +1,5 @@ use tui::{ - style::{Color, Modifier}, + style::{Color, Modifier, Style}, widgets::BorderType, }; @@ -46,6 +46,7 @@ impl Styles { text_style: hex!("#e5e9f0"), selected_text_style: hex!("#2e3440").bg(hex_colour!("#88c0d0")), table_header_style: hex!("#81a1c1").add_modifier(Modifier::BOLD), + general_widget_style: Style::default(), widget_title_style: hex!("#e5e9f0"), graph_style: hex!("#e5e9f0"), graph_legend_style: hex!("#e5e9f0"), @@ -99,6 +100,7 @@ impl Styles { text_style: hex!("#2e3440"), selected_text_style: hex!("#f5f5f5").bg(hex_colour!("#5e81ac")), table_header_style: hex!("#5e81ac").add_modifier(Modifier::BOLD), + general_widget_style: Style::default(), widget_title_style: hex!("#2e3440"), graph_style: hex!("#2e3440"), graph_legend_style: hex!("#2e3440"), diff --git a/src/options/config/style/utils.rs b/src/options/config/style/utils.rs index dc15b251..16801625 100644 --- a/src/options/config/style/utils.rs +++ b/src/options/config/style/utils.rs @@ -96,8 +96,8 @@ fn convert_name_to_colour(color_name: &str) -> Result { "white" => Ok(Color::White), _ => Err(format!( "'{color_name}' is an invalid named color. - -The following are supported named colors: + +The following are supported named colors: +--------+-------------+---------------------+ | Reset | Magenta | Light Yellow | +--------+-------------+---------------------+ @@ -233,6 +233,27 @@ macro_rules! set_colour { }; } +macro_rules! set_bg_colour { + ($palette_field:expr, $config_location:expr, $field:tt) => { + if let Some(colour) = &(opt!($config_location.as_ref()?.$field.as_ref())) { + $palette_field = $palette_field.bg( + crate::options::config::style::utils::str_to_colour(&colour.0).map_err(|err| { + match stringify!($config_location).split_once(".") { + Some((_, loc)) => crate::options::OptionError::config(format!( + "Please update 'styles.{loc}.{}' in your config file. {err}", + stringify!($field) + )), + None => crate::options::OptionError::config(format!( + "Please update 'styles.{}' in your config file. {err}", + stringify!($field) + )), + } + })?, + ); + } + }; +} + /// Set `palette_field` to the value in `config_location` for `field`. macro_rules! set_colour_list { ($palette_field:expr, $config_location:expr, $field:tt) => { @@ -259,6 +280,7 @@ macro_rules! set_colour_list { } pub(super) use opt; +pub(super) use set_bg_colour; pub(super) use set_colour; pub(super) use set_colour_list; pub(super) use set_style; @@ -513,6 +535,32 @@ mod test { Ok(()) } + #[test] + fn test_set_bg_colour() -> anyhow::Result<()> { + let mut s = Style::default().bg(Color::Black); + let dummy = DummyConfig { + inner: Some(InnerDummyConfig::default()), + }; + + set_bg_colour!(s, &dummy.inner, color_a); + assert_eq!(s.fg, None); + assert_eq!(s.bg.unwrap(), Color::Black); + + set_bg_colour!(s, &dummy.inner, color_b); + assert_eq!(s.fg, None); + assert_eq!(s.bg.unwrap(), Color::Red); + + set_bg_colour!(s, &dummy.inner, color_c); + assert_eq!(s.fg, None); + assert_eq!(s.bg.unwrap(), Color::Rgb(255, 255, 255)); + + set_bg_colour!(s, &dummy.inner, color_d); + assert_eq!(s.fg, None); + assert_eq!(s.bg.unwrap(), Color::Rgb(0, 0, 0)); + + Ok(()) + } + #[test] fn test_bad_set_colour() { let mut _s = Style::default().fg(Color::Black); diff --git a/src/options/config/style/widgets.rs b/src/options/config/style/widgets.rs index 6c33c55a..dcedec64 100644 --- a/src/options/config/style/widgets.rs +++ b/src/options/config/style/widgets.rs @@ -33,4 +33,7 @@ pub(crate) struct WidgetStyle { /// Widget borders type. pub(crate) widget_border_type: Option, + + /// Background color for widgets. + pub(crate) bg_color: Option, }