mirror of
https://github.com/ClementTsang/bottom.git
synced 2026-05-04 05:50:42 +00:00
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:
@@ -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 }` |
|
||||||
|
|||||||
@@ -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"}
|
||||||
|
|
||||||
|
|||||||
@@ -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"]
|
||||||
|
|
||||||
|
|||||||
@@ -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": [
|
||||||
|
|||||||
@@ -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 };
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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],
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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
@@ -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"}
|
||||||
|
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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"),
|
||||||
|
|||||||
@@ -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"),
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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>,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user