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>
This commit is contained in:
dastarruer
2026-04-11 03:59:25 -04:00
committed by GitHub
parent 8a38f89113
commit 8cb217cd19
27 changed files with 200 additions and 67 deletions
+1
View File
@@ -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. - [#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. - [#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 ### Other
@@ -162,6 +162,7 @@ These can be set under `[styles.widgets]`:
| `border_color` | The colour of the widgets' borders | `border_color = "white"` | | `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"` | | `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 }` | | `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 }` | | `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 }` | | `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 }` | | `disabled_text` | Text styling for text when representing something that is disabled | `disabled_text = { color = "black", bg_color = "blue", bold = true }` |
+2 -1
View File
@@ -295,7 +295,8 @@
#text = {color = "gray"} #text = {color = "gray"}
#selected_text = {color = "black", bg_color = "light blue"} #selected_text = {color = "black", bg_color = "light blue"}
#disabled_text = {color = "dark gray"} #disabled_text = {color = "dark gray"}
# Disabled by default
#bg_color = "black"
# Only on Linux # Only on Linux
#thread_text = {color = "green"} #thread_text = {color = "green"}
+1
View File
@@ -19,3 +19,4 @@ theme = "gruvbox"
[processes] [processes]
columns = ["PID", "Name", "CPU%", "Mem%", "Rps", "Wps", "TRead", "TWrite", "State", "Time", "Virt"] columns = ["PID", "Name", "CPU%", "Mem%", "Rps", "Wps", "TRead", "TWrite", "State", "Time", "Virt"]
+11
View File
@@ -1113,6 +1113,17 @@
"description": "General styling for generic widgets.", "description": "General styling for generic widgets.",
"type": "object", "type": "object",
"properties": { "properties": {
"bg_color": {
"description": "Background color for widgets.",
"anyOf": [
{
"$ref": "#/$defs/ColorStr"
},
{
"type": "null"
}
]
},
"border_color": { "border_color": {
"description": "The colour of the widgets' borders.", "description": "The colour of the widgets' borders.",
"anyOf": [ "anyOf": [
+8
View File
@@ -120,6 +120,10 @@ impl Painter {
// TODO: Make drawing dialog generic. // TODO: Make drawing dialog generic.
if app_state.help_dialog_state.is_showing_help { 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 gen_help_len = GENERAL_HELP_TEXT.len() as u16 + 3;
let border_len = terminal_height.saturating_sub(gen_help_len) / 2; let border_len = terminal_height.saturating_sub(gen_help_len) / 2;
let [_, vertical_dialog_chunk, _] = Layout::default() let [_, vertical_dialog_chunk, _] = Layout::default()
@@ -178,6 +182,10 @@ impl Painter {
self.draw_help_dialog(f, app_state, middle_dialog_chunk); self.draw_help_dialog(f, app_state, middle_dialog_chunk);
} else if app_state.process_kill_dialog.is_open() { } 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? // 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 horizontal_padding = if terminal_width < 100 { 0 } else { 5 };
let vertical_padding = if terminal_height < 100 { 0 } else { 5 }; let vertical_padding = if terminal_height < 100 { 0 } else { 5 };
+12 -5
View File
@@ -8,7 +8,7 @@ use tui::{
Frame, Frame,
layout::{Constraint, Direction, Layout, Rect}, layout::{Constraint, Direction, Layout, Rect},
text::{Line, Span, Text}, text::{Line, Span, Text},
widgets::{Block, Cell, Row, Table}, widgets::{Block, Cell, Padding, Row, Table},
}; };
use super::{ use super::{
@@ -77,8 +77,13 @@ where
self.styling.border_style self.styling.border_style
}; };
let mut block = widget_block(self.props.is_basic, is_selected, self.styling.border_type) let mut block = widget_block(
.border_style(border_style); 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 let Some((left_title, right_title)) = self.generate_title(draw_info, data_len) {
if !self.props.is_basic { if !self.props.is_basic {
@@ -135,11 +140,13 @@ where
let draw_loc = draw_info.loc; let draw_loc = draw_info.loc;
let margined_draw_loc = Layout::default() let margined_draw_loc = Layout::default()
.constraints([Constraint::Percentage(100)]) .constraints([Constraint::Percentage(100)])
.horizontal_margin(u16::from(self.props.is_basic && !draw_info.is_on_widget()))
.direction(Direction::Horizontal) .direction(Direction::Horizontal)
.split(draw_loc)[0]; .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_width, inner_height) = {
let inner_rect = block.inner(margined_draw_loc); let inner_rect = block.inner(margined_draw_loc);
@@ -11,6 +11,7 @@ pub struct DataTableStyling {
pub text_style: Style, pub text_style: Style,
pub highlighted_text_style: Style, pub highlighted_text_style: Style,
pub title_style: Style, pub title_style: Style,
pub general_widget_style: Style,
} }
impl DataTableStyling { impl DataTableStyling {
@@ -23,6 +24,7 @@ impl DataTableStyling {
text_style: styles.text_style, text_style: styles.text_style,
highlighted_text_style: styles.selected_text_style, highlighted_text_style: styles.selected_text_style,
title_style: styles.widget_title_style, title_style: styles.widget_title_style,
general_widget_style: styles.general_widget_style,
} }
} }
} }
+13 -3
View File
@@ -64,6 +64,9 @@ pub struct TimeGraph<'a> {
/// The graph style. /// The graph style.
pub graph_style: Style, pub graph_style: Style,
/// The background color
pub general_widget_style: Style,
/// The border style. /// The border style.
pub border_style: Style, pub border_style: Style,
@@ -150,9 +153,14 @@ impl TimeGraph<'_> {
let data = graph_data.into_iter().map(create_dataset).collect(); let data = graph_data.into_iter().map(create_dataset).collect();
let block = { let block = {
let mut b = widget_block(false, self.is_selected, self.border_type) let mut b = widget_block(
.border_style(self.border_style) false,
.title_top(Line::styled(self.title.as_ref(), self.title_style)); 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 { if self.is_expanded {
b = b.title_top(Line::styled(" Esc to go back ", self.title_style).right_aligned()) 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) .x_axis(x_axis)
.y_axis(y_axis) .y_axis(y_axis)
.marker(self.marker) .marker(self.marker)
.style(self.general_widget_style)
.legend_style(self.graph_style) .legend_style(self.graph_style)
.legend_position(self.legend_position) .legend_position(self.legend_position)
.hidden_legend_constraints( .hidden_legend_constraints(
@@ -232,6 +241,7 @@ mod test {
y_bounds: AxisBound::Max(100.5), y_bounds: AxisBound::Max(100.5),
y_labels: &Y_LABELS, y_labels: &Y_LABELS,
graph_style: Style::default().fg(Color::Red), graph_style: Style::default().fg(Color::Red),
general_widget_style: Style::default().bg(Color::Black),
border_style: Style::default().fg(Color::Blue), border_style: Style::default().fg(Color::Blue),
border_type: BorderType::Plain, border_type: BorderType::Plain,
is_selected: false, is_selected: false,
@@ -35,7 +35,7 @@ pub(crate) struct PercentTimeGraph<'a> {
pub(crate) current_widget: u64, pub(crate) current_widget: u64,
/// Whether the current widget is expanded. /// Whether the current widget is expanded.
/// ///
/// This is mostly used as a shared mutability workaround due to [`App`] /// This is mostly used as a shared mutability workaround due to [`App`]
/// being a giant state struct. /// being a giant state struct.
pub(crate) is_expanded: bool, pub(crate) is_expanded: bool,
@@ -71,6 +71,7 @@ impl<'a> PercentTimeGraph<'a> {
}; };
let graph_style = self.styles.graph_style; 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 border_style = get_border_style(self.styles, self.widget_id, self.current_widget);
let title_style = self.styles.widget_title_style; let title_style = self.styles.widget_title_style;
let border_type = self.styles.border_type; let border_type = self.styles.border_type;
@@ -81,6 +82,7 @@ impl<'a> PercentTimeGraph<'a> {
y_bounds: Y_BOUNDS, y_bounds: Y_BOUNDS,
y_labels: &Y_LABELS, y_labels: &Y_LABELS,
graph_style, graph_style,
general_widget_style,
border_style, border_style,
border_type, border_type,
title: self.title, title: self.title,
+4
View File
@@ -115,6 +115,10 @@ impl Painter {
.horizontal_margin(1) .horizontal_margin(1)
.split(draw_loc); .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( f.render_widget(
Paragraph::new(left_arrow_text).block(Block::default()), Paragraph::new(left_arrow_text).block(Block::default()),
margined_draw_loc[0], margined_draw_loc[0],
+1 -2
View File
@@ -41,8 +41,7 @@ impl Painter {
pub fn draw_help_dialog(&self, f: &mut Frame<'_>, app_state: &mut App, draw_loc: Rect) { 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 styled_help_text = self.help_text_lines();
let block = dialog_block(self.styles.border_type) let block = dialog_block(self.styles.border_type, self.styles.border_style)
.border_style(self.styles.border_style)
.title_top(Line::styled(" Help ", self.styles.widget_title_style)) .title_top(Line::styled(" Help ", self.styles.widget_title_style))
.title_top( .title_top(
Line::styled(" Esc to close ", self.styles.widget_title_style).right_aligned(), Line::styled(" Esc to close ", self.styles.widget_title_style).right_aligned(),
+4 -8
View File
@@ -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(title)
.title_top(Line::styled(" Esc to close ", styles.widget_title_style).right_aligned()) .title_top(Line::styled(" Esc to close ", styles.widget_title_style).right_aligned());
.style(styles.border_style)
.border_style(styles.border_style);
let num_lines = text.line_count(block.inner(draw_area).width) as u16; let num_lines = text.line_count(block.inner(draw_area).width) as u16;
@@ -811,11 +809,9 @@ impl ProcessKillDialog {
.alignment(Alignment::Center) .alignment(Alignment::Center)
.wrap(Wrap { trim: true }); .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(title)
.title_top(Line::styled(" Esc to close ", styles.widget_title_style).right_aligned()) .title_top(Line::styled(" Esc to close ", styles.widget_title_style).right_aligned());
.style(styles.border_style)
.border_style(styles.border_style);
let num_lines = text.line_count(block.inner(draw_area).width) as u16; let num_lines = text.line_count(block.inner(draw_area).width) as u16;
+15 -9
View File
@@ -2,6 +2,7 @@ use std::time::Instant;
use tui::{ use tui::{
layout::Rect, layout::Rect,
style::Style,
widgets::{Block, BorderType, Borders}, widgets::{Block, BorderType, Borders},
}; };
@@ -29,26 +30,31 @@ pub fn should_hide_x_label(
} }
/// Return a widget block. /// Return a widget block.
pub fn widget_block(is_basic: bool, is_selected: bool, border_type: BorderType) -> Block<'static> { pub fn widget_block(
let mut block = Block::default().border_type(border_type); is_basic: bool, is_selected: bool, border_type: BorderType, widget_style: Style,
) -> Block<'static> {
if is_basic { if is_basic {
if is_selected { if is_selected {
block = block.borders(SIDE_BORDERS); Block::default()
.border_type(border_type)
.style(widget_style)
.borders(SIDE_BORDERS)
} else { } else {
block = block.borders(Borders::empty()); Block::default().style(widget_style)
} }
} else { } else {
block = block.borders(Borders::all()); Block::default()
.border_type(border_type)
.style(widget_style)
.borders(Borders::all())
} }
block
} }
/// Return a dialog 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() Block::default()
.border_type(border_type) .border_type(border_type)
.border_style(border_style)
.borders(Borders::all()) .borders(Borders::all())
} }
+1
View File
@@ -51,6 +51,7 @@ impl Painter {
app_state.app_config_fields.use_basic_mode, app_state.app_config_fields.use_basic_mode,
is_selected, is_selected,
self.styles.border_type, self.styles.border_type,
self.styles.general_widget_style,
) )
.border_style(border_style) .border_style(border_style)
.title_top(Line::styled(" Battery ", self.styles.widget_title_style)); .title_top(Line::styled(" Battery ", self.styles.widget_title_style));
+10 -7
View File
@@ -33,13 +33,16 @@ impl Painter {
// If not, then add a new column. Then, from this, split the row space across ALL columns. // If not, then add a new column. Then, from this, split the row space across ALL columns.
// From there, generate the desired lengths. // From there, generate the desired lengths.
if app_state.current_widget.widget_id == widget_id { f.render_widget(
f.render_widget( widget_block(
widget_block(true, true, self.styles.border_type) true,
.border_style(self.styles.highlighted_border_style), app_state.current_widget.widget_id == widget_id,
draw_loc, 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? // TODO: This is pretty ugly. Is there a better way of doing it?
let mut avg_index = cpu_data.len() + 1; let mut avg_index = cpu_data.len() + 1;
+10 -7
View File
@@ -46,13 +46,16 @@ impl Painter {
) { ) {
let mut draw_widgets: Vec<PipeGauge<'_>> = Vec::new(); let mut draw_widgets: Vec<PipeGauge<'_>> = Vec::new();
if app_state.current_widget.widget_id == widget_id { f.render_widget(
f.render_widget( widget_block(
widget_block(true, true, self.styles.border_type) true,
.border_style(self.styles.highlighted_border_style), app_state.current_widget.widget_id == widget_id,
draw_loc, 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(); let data = app_state.data_store.get_data();
+10 -7
View File
@@ -21,13 +21,16 @@ impl Painter {
) { ) {
let show_packets = app_state.app_config_fields.network_show_packets; let show_packets = app_state.app_config_fields.network_show_packets;
if app_state.current_widget.widget_id == widget_id { f.render_widget(
f.render_widget( widget_block(
widget_block(true, true, self.styles.border_type) true,
.border_style(self.styles.highlighted_border_style), app_state.current_widget.widget_id == widget_id,
draw_loc, 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 use_binary_prefix = app_state.app_config_fields.network_use_binary_prefix;
let network_data = &(app_state.data_store.get_data().network_harvest); let network_data = &(app_state.data_store.get_data().network_harvest);
+17 -9
View File
@@ -5,7 +5,7 @@ use tui::{
layout::{Constraint, Direction, Layout, Rect}, layout::{Constraint, Direction, Layout, Rect},
symbols::Marker, symbols::Marker,
text::Text, text::Text,
widgets::{Block, Borders, Row, Table}, widgets::{Row, Table},
}; };
use crate::{ use crate::{
@@ -13,7 +13,7 @@ use crate::{
canvas::{ canvas::{
Painter, Painter,
components::time_graph::{AxisBound, ChartScaling, GraphData, TimeGraph}, 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}, widgets::{PacketInfo, calculate_packet_info},
}, },
utils::{ utils::{
@@ -267,6 +267,7 @@ impl Painter {
y_bounds, y_bounds,
y_labels: &(y_labels.into_iter().map(Into::into).collect::<Vec<_>>()), y_labels: &(y_labels.into_iter().map(Into::into).collect::<Vec<_>>()),
graph_style: self.styles.graph_style, graph_style: self.styles.graph_style,
general_widget_style: self.styles.general_widget_style,
border_style, border_style,
border_type: self.styles.border_type, border_type: self.styles.border_type,
title: " Network ".into(), title: " Network ".into(),
@@ -348,6 +349,19 @@ impl Painter {
let column_width = draw_loc.width.saturating_sub(2) / num_columns as u16; let column_width = draw_loc.width.saturating_sub(2) / num_columns as u16;
// Draw // 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( f.render_widget(
Table::new( Table::new(
total_network, total_network,
@@ -356,13 +370,7 @@ impl Painter {
.collect::<Vec<_>>()), .collect::<Vec<_>>()),
) )
.header(Row::new(headers).style(self.styles.table_header_style)) .header(Row::new(headers).style(self.styles.table_header_style))
.block(Block::default().borders(Borders::ALL).border_style( .block(block)
if app_state.current_widget.widget_id == widget_id {
self.styles.highlighted_border_style
} else {
self.styles.border_style
},
))
.style(self.styles.text_style), .style(self.styles.text_style),
draw_loc, draw_loc,
); );
+7 -2
View File
@@ -254,8 +254,13 @@ impl Painter {
}; };
let process_search_block = { let process_search_block = {
let mut block = widget_block(is_basic, is_selected, self.styles.border_type) let mut block = widget_block(
.border_style(current_border_style); is_basic,
is_selected,
self.styles.border_type,
self.styles.general_widget_style,
)
.border_style(current_border_style);
if !is_basic { if !is_basic {
block = block.title_top( block = block.title_top(
+2 -1
View File
@@ -541,7 +541,8 @@ pub(crate) const CONFIG_TEXT: &str = r#"# This is a default config file for bott
#text = {color = "gray"} #text = {color = "gray"}
#selected_text = {color = "black", bg_color = "light blue"} #selected_text = {color = "black", bg_color = "light blue"}
#disabled_text = {color = "dark gray"} #disabled_text = {color = "dark gray"}
# Disabled by default
#bg_color = "black"
# Only on Linux # Only on Linux
#thread_text = {color = "green"} #thread_text = {color = "green"}
+5 -1
View File
@@ -25,7 +25,9 @@ use utils::{opt, set_colour, set_colour_list, set_style};
use widgets::WidgetStyle; use widgets::WidgetStyle;
use super::Config; 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)] #[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))]
@@ -117,6 +119,7 @@ pub struct Styles {
pub(crate) selected_text_style: Style, pub(crate) selected_text_style: Style,
pub(crate) table_header_style: Style, pub(crate) table_header_style: Style,
pub(crate) widget_title_style: Style, pub(crate) widget_title_style: Style,
pub(crate) general_widget_style: Style,
pub(crate) graph_style: Style, pub(crate) graph_style: Style,
pub(crate) graph_legend_style: Style, pub(crate) graph_legend_style: Style,
pub(crate) high_battery: Style, pub(crate) high_battery: Style,
@@ -207,6 +210,7 @@ impl Styles {
set_style!(self.graph_legend_style, config.graphs, legend_text); set_style!(self.graph_legend_style, config.graphs, legend_text);
// General widget 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.widget_title_style, config.widgets, widget_title);
set_style!(self.text_style, config.widgets, text); set_style!(self.text_style, config.widgets, text);
set_style!(self.selected_text_style, config.widgets, selected_text); set_style!(self.selected_text_style, config.widgets, selected_text);
@@ -59,6 +59,7 @@ impl Styles {
selected_text_style: DEFAULT_SELECTED_TEXT_STYLE, selected_text_style: DEFAULT_SELECTED_TEXT_STYLE,
table_header_style: color!(HIGHLIGHT_COLOUR).add_modifier(Modifier::BOLD), table_header_style: color!(HIGHLIGHT_COLOUR).add_modifier(Modifier::BOLD),
widget_title_style: color!(TEXT_COLOUR), widget_title_style: color!(TEXT_COLOUR),
general_widget_style: Style::default(),
graph_style: color!(TEXT_COLOUR), graph_style: color!(TEXT_COLOUR),
graph_legend_style: color!(TEXT_COLOUR), graph_legend_style: color!(TEXT_COLOUR),
high_battery: color!(Color::Green), high_battery: color!(Color::Green),
+3 -1
View File
@@ -1,5 +1,5 @@
use tui::{ use tui::{
style::{Color, Modifier}, style::{Color, Modifier, Style},
widgets::BorderType, widgets::BorderType,
}; };
@@ -58,6 +58,7 @@ impl Styles {
text_style: hex!("#ebdbb2"), text_style: hex!("#ebdbb2"),
selected_text_style: hex!("#1d2021").bg(hex_colour!("#ebdbb2")), selected_text_style: hex!("#1d2021").bg(hex_colour!("#ebdbb2")),
table_header_style: hex!("#83a598").add_modifier(Modifier::BOLD), table_header_style: hex!("#83a598").add_modifier(Modifier::BOLD),
general_widget_style: Style::default(),
widget_title_style: hex!("#ebdbb2"), widget_title_style: hex!("#ebdbb2"),
graph_style: hex!("#ebdbb2"), graph_style: hex!("#ebdbb2"),
graph_legend_style: hex!("#ebdbb2"), graph_legend_style: hex!("#ebdbb2"),
@@ -123,6 +124,7 @@ impl Styles {
text_style: hex!("#3c3836"), text_style: hex!("#3c3836"),
selected_text_style: hex!("#ebdbb2").bg(hex_colour!("#3c3836")), selected_text_style: hex!("#ebdbb2").bg(hex_colour!("#3c3836")),
table_header_style: hex!("#076678").add_modifier(Modifier::BOLD), table_header_style: hex!("#076678").add_modifier(Modifier::BOLD),
general_widget_style: Style::default(),
widget_title_style: hex!("#3c3836"), widget_title_style: hex!("#3c3836"),
graph_style: hex!("#3c3836"), graph_style: hex!("#3c3836"),
graph_legend_style: hex!("#3c3836"), graph_legend_style: hex!("#3c3836"),
+3 -1
View File
@@ -1,5 +1,5 @@
use tui::{ use tui::{
style::{Color, Modifier}, style::{Color, Modifier, Style},
widgets::BorderType, widgets::BorderType,
}; };
@@ -46,6 +46,7 @@ impl Styles {
text_style: hex!("#e5e9f0"), text_style: hex!("#e5e9f0"),
selected_text_style: hex!("#2e3440").bg(hex_colour!("#88c0d0")), selected_text_style: hex!("#2e3440").bg(hex_colour!("#88c0d0")),
table_header_style: hex!("#81a1c1").add_modifier(Modifier::BOLD), table_header_style: hex!("#81a1c1").add_modifier(Modifier::BOLD),
general_widget_style: Style::default(),
widget_title_style: hex!("#e5e9f0"), widget_title_style: hex!("#e5e9f0"),
graph_style: hex!("#e5e9f0"), graph_style: hex!("#e5e9f0"),
graph_legend_style: hex!("#e5e9f0"), graph_legend_style: hex!("#e5e9f0"),
@@ -99,6 +100,7 @@ impl Styles {
text_style: hex!("#2e3440"), text_style: hex!("#2e3440"),
selected_text_style: hex!("#f5f5f5").bg(hex_colour!("#5e81ac")), selected_text_style: hex!("#f5f5f5").bg(hex_colour!("#5e81ac")),
table_header_style: hex!("#5e81ac").add_modifier(Modifier::BOLD), table_header_style: hex!("#5e81ac").add_modifier(Modifier::BOLD),
general_widget_style: Style::default(),
widget_title_style: hex!("#2e3440"), widget_title_style: hex!("#2e3440"),
graph_style: hex!("#2e3440"), graph_style: hex!("#2e3440"),
graph_legend_style: hex!("#2e3440"), graph_legend_style: hex!("#2e3440"),
+50 -2
View File
@@ -96,8 +96,8 @@ fn convert_name_to_colour(color_name: &str) -> Result<Color, String> {
"white" => Ok(Color::White), "white" => Ok(Color::White),
_ => Err(format!( _ => Err(format!(
"'{color_name}' is an invalid named color. "'{color_name}' is an invalid named color.
The following are supported named colors: The following are supported named colors:
+--------+-------------+---------------------+ +--------+-------------+---------------------+
| Reset | Magenta | Light Yellow | | 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`. /// Set `palette_field` to the value in `config_location` for `field`.
macro_rules! set_colour_list { macro_rules! set_colour_list {
($palette_field:expr, $config_location:expr, $field:tt) => { ($palette_field:expr, $config_location:expr, $field:tt) => {
@@ -259,6 +280,7 @@ macro_rules! set_colour_list {
} }
pub(super) use opt; pub(super) use opt;
pub(super) use set_bg_colour;
pub(super) use set_colour; pub(super) use set_colour;
pub(super) use set_colour_list; pub(super) use set_colour_list;
pub(super) use set_style; pub(super) use set_style;
@@ -513,6 +535,32 @@ mod test {
Ok(()) 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] #[test]
fn test_bad_set_colour() { fn test_bad_set_colour() {
let mut _s = Style::default().fg(Color::Black); let mut _s = Style::default().fg(Color::Black);
+3
View File
@@ -33,4 +33,7 @@ pub(crate) struct WidgetStyle {
/// Widget borders type. /// Widget borders type.
pub(crate) widget_border_type: Option<WidgetBorderType>, pub(crate) widget_border_type: Option<WidgetBorderType>,
/// Background color for widgets.
pub(crate) bg_color: Option<ColorStr>,
} }