feature: support simple colour settings for text fields too (#1511)

* feature: support simple colour settings for text fields too

* also add 'color' back to some options

* tests
This commit is contained in:
Clement Tsang 2024-07-30 07:15:23 +00:00 committed by GitHub
parent 95905d7a2b
commit f091ebdc6a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 442 additions and 189 deletions

View File

@ -83,6 +83,14 @@ field = { color = "black", bg_color = "blue", bold = false }
All fields are optional; by default if `bg_color` is not set then there will be no background color. All fields are optional; by default if `bg_color` is not set then there will be no background color.
If you _just_ want to style text by setting the foreground colour, for brevity, then you can also just set the field
to be the colour itself. For example:
```toml
[styles.widgets]
selected_text = "#fff"
```
### Configuration ### Configuration
#### CPU #### CPU
@ -99,34 +107,34 @@ These can be set under `[styles.cpu]`:
These can be set under `[styles.memory]`: These can be set under `[styles.memory]`:
| Config field | Details | Examples | | Config field | Details | Examples |
| ------------ | ------------------------------------------------------------------------------ | --------------------------------- | | ------------- | ------------------------------------------------------------------------------ | --------------------------------------- |
| `ram` | The colour of the RAM label and graph line | `ram = "Red"` | | `ram_color` | The colour of the RAM label and graph line | `ram_color = "Red"` |
| `cache` | The colour of the cache label and graph line. Does not do anything on Windows. | `cache = "#ffffff"` | | `cache_color` | The colour of the cache label and graph line. Does not do anything on Windows. | `cache_color = "#ffffff"` |
| `swap` | The colour of the swap label and graph line | `swap = "255, 0, 255"` | | `swap_color` | The colour of the swap label and graph line | `swap_color = "255, 0, 255"` |
| `arc` | The colour of the ARC label and graph line | `arc = "Blue"` | | `arc_color` | The colour of the ARC label and graph line | `arc_color = "Blue"` |
| `gpus` | Colour of each GPU's memory label and graph line. Read in order. | `gpus = ["Red", "Blue", "Green"]` | | `gpu_colors` | Colour of each GPU's memory label and graph line. Read in order. | `gpu_colors = ["Red", "Blue", "Green"]` |
#### Network #### Network
These can be set under `[styles.network]`: These can be set under `[styles.network]`:
| Config field | Details | Examples | | Config field | Details | Examples |
| ------------ | --------------------------------------------------------- | ---------------------- | | ---------------- | --------------------------------------------------------- | ---------------------------- |
| `rx` | The colour of the RX (download) label and graph line | `rx = "Red"` | | `rx_color` | The colour of the RX (download) label and graph line | `rx_color = "Red"` |
| `tx` | The colour of the TX (upload) label and graph line. | `tx = "#ffffff"` | | `tx_color` | The colour of the TX (upload) label and graph line | `tx_color = "#ffffff"` |
| `rx_total` | The colour of the total RX (download) label in basic mode | `rx_total = "0, 0, 0"` | | `rx_total_color` | The colour of the total RX (download) label in basic mode | `rx_total_color = "0, 0, 0"` |
| `tx_total` | The colour of the total TX (upload) label in basic mode | `tx_total = "#000"` | | `tx_total_color` | The colour of the total TX (upload) label in basic mode | `tx_total_color = "#000"` |
#### Battery #### Battery
These can be set under `[styles.battery]`: These can be set under `[styles.battery]`:
| Config field | Details | Examples | | Config field | Details | Examples |
| ---------------- | ------------------------------------------------------------------------ | ---------------------------- | | ---------------------- | ------------------------------------------------------------------------ | ---------------------------------- |
| `high_battery` | The colour of the battery widget bar when the battery is over 50% | `high_battery = "Red"` | | `high_battery_color` | The colour of the battery widget bar when the battery is over 50% | `high_battery_color = "Red"` |
| `medium_battery` | The colour of the battery widget bar when the battery between 10% to 50% | `medium_battery = "#ffffff"` | | `medium_battery_color` | The colour of the battery widget bar when the battery between 10% to 50% | `medium_battery_color = "#ffffff"` |
| `low_battery` | The colour of the battery widget bar when the battery is under 10% | `low_battery = "0, 0, 0"` | | `low_battery_color` | The colour of the battery widget bar when the battery is under 10% | `low_battery_color = "0, 0, 0"` |
#### Tables #### Tables
@ -149,11 +157,11 @@ These can be set under `[styles.graphs]`:
These can be set under `[styles.widgets]`: These can be set under `[styles.widgets]`:
| Config field | Details | Examples | | Config field | Details | Examples |
| ----------------- | ------------------------------------------------------------ | --------------------------------------------------------------------- | | ----------------------- | ------------------------------------------------------------ | --------------------------------------------------------------------- |
| `border` | The colour of the widgets' borders | `border = "white"` | | `border_color` | The colour of the widgets' borders | `border_color = "white"` |
| `selected_border` | The colour of a widget's borders when the widget is selected | `selected_border = "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 }` |
| `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 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 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 }` |

View File

@ -147,22 +147,22 @@
#cpu_core_colors = ["light magenta", "light yellow", "light cyan", "light green", "light blue", "cyan", "green", "blue"] #cpu_core_colors = ["light magenta", "light yellow", "light cyan", "light green", "light blue", "cyan", "green", "blue"]
#[styles.memory] #[styles.memory]
#ram = "light magenta" #ram_color = "light magenta"
#cache = "light red" #cache_color = "light red"
#swap = "light yellow" #swap_color = "light yellow"
#arc = "light cyan" #arc_color = "light cyan"
#gpus = ["light blue", "light red", "cyan", "green", "blue", "red"] #gpu_colors = ["light blue", "light red", "cyan", "green", "blue", "red"]
#[styles.network] #[styles.network]
#rx = "light magenta" #rx_color = "light magenta"
#tx = "light yellow" #tx_color = "light yellow"
#rx_total = "light cyan" #rx_total_color = "light cyan"
#tx_total = "light green" #tx_total_color = "light green"
#[styles.battery] #[styles.battery]
#high_battery = "green" #high_battery_color = "green"
#medium_battery = "yellow" #medium_battery_color = "yellow"
#low_battery = "red" #low_battery_color = "red"
#[styles.tables] #[styles.tables]
#headers = {color = "light blue"} #headers = {color = "light blue"}
@ -172,8 +172,8 @@
#legend_text = {color = "gray"} #legend_text = {color = "gray"}
#[styles.widgets] #[styles.widgets]
#border = "gray" #border_color = "gray"
#selected_border = "light blue" #selected_border_color = "light blue"
#widget_title = {color = "gray"} #widget_title = {color = "gray"}
#text = {color = "gray"} #text = {color = "gray"}
#selected_text = {color = "black", bg_color = "light blue"} #selected_text = {color = "black", bg_color = "light blue"}

View File

@ -90,7 +90,8 @@
"description": "Styling specific to the battery widget.", "description": "Styling specific to the battery widget.",
"type": "object", "type": "object",
"properties": { "properties": {
"high_battery": { "high_battery_color": {
"description": "The colour of the battery widget bar when the battery is over 50%.",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/ColorStr" "$ref": "#/definitions/ColorStr"
@ -100,7 +101,8 @@
} }
] ]
}, },
"low_battery": { "low_battery_color": {
"description": "The colour of the battery widget bar when the battery is under 10%.",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/ColorStr" "$ref": "#/definitions/ColorStr"
@ -110,7 +112,8 @@
} }
] ]
}, },
"medium_battery": { "medium_battery_color": {
"description": "The colour of the battery widget bar when the battery between 10% to 50%.",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/ColorStr" "$ref": "#/definitions/ColorStr"
@ -147,6 +150,7 @@
"type": "object", "type": "object",
"properties": { "properties": {
"all_entry_color": { "all_entry_color": {
"description": "The colour of the \"All\" CPU label.",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/ColorStr" "$ref": "#/definitions/ColorStr"
@ -157,6 +161,7 @@
] ]
}, },
"avg_entry_color": { "avg_entry_color": {
"description": "The colour of the average CPU label and graph line.",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/ColorStr" "$ref": "#/definitions/ColorStr"
@ -167,6 +172,7 @@
] ]
}, },
"cpu_core_colors": { "cpu_core_colors": {
"description": "Colour of each CPU threads' label and graph line. Read in order.",
"type": [ "type": [
"array", "array",
"null" "null"
@ -481,6 +487,7 @@
"type": "object", "type": "object",
"properties": { "properties": {
"graph_color": { "graph_color": {
"description": "The general colour of the parts of the graph.",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/ColorStr" "$ref": "#/definitions/ColorStr"
@ -491,6 +498,7 @@
] ]
}, },
"legend_text": { "legend_text": {
"description": "Text styling for graph's legend text.",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/TextStyleConfig" "$ref": "#/definitions/TextStyleConfig"
@ -536,7 +544,8 @@
"description": "Styling specific to the memory widget.", "description": "Styling specific to the memory widget.",
"type": "object", "type": "object",
"properties": { "properties": {
"arc": { "arc_color": {
"description": "The colour of the ARC label and graph line.",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/ColorStr" "$ref": "#/definitions/ColorStr"
@ -546,7 +555,8 @@
} }
] ]
}, },
"cache": { "cache_color": {
"description": "The colour of the cache label and graph line. Does not do anything on Windows.",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/ColorStr" "$ref": "#/definitions/ColorStr"
@ -556,7 +566,8 @@
} }
] ]
}, },
"gpus": { "gpu_colors": {
"description": "Colour of each GPU's memory label and graph line. Read in order.",
"type": [ "type": [
"array", "array",
"null" "null"
@ -565,7 +576,8 @@
"$ref": "#/definitions/ColorStr" "$ref": "#/definitions/ColorStr"
} }
}, },
"ram": { "ram_color": {
"description": "The colour of the RAM label and graph line.",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/ColorStr" "$ref": "#/definitions/ColorStr"
@ -575,7 +587,8 @@
} }
] ]
}, },
"swap": { "swap_color": {
"description": "The colour of the swap label and graph line.",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/ColorStr" "$ref": "#/definitions/ColorStr"
@ -608,7 +621,8 @@
"description": "Styling specific to the network widget.", "description": "Styling specific to the network widget.",
"type": "object", "type": "object",
"properties": { "properties": {
"rx": { "rx_color": {
"description": "The colour of the RX (download) label and graph line.",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/ColorStr" "$ref": "#/definitions/ColorStr"
@ -618,8 +632,8 @@
} }
] ]
}, },
"rx_total": { "rx_total_color": {
"description": "Set the colour of the \"rx total\" text. This only affects basic mode.", "description": "he colour of the total RX (download) label in basic mode.",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/ColorStr" "$ref": "#/definitions/ColorStr"
@ -629,7 +643,8 @@
} }
] ]
}, },
"tx": { "tx_color": {
"description": "The colour of the TX (upload) label and graph line.",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/ColorStr" "$ref": "#/definitions/ColorStr"
@ -639,8 +654,8 @@
} }
] ]
}, },
"tx_total": { "tx_total_color": {
"description": "Set the colour of the \"tx total\" text. This only affects basic mode.", "description": "The colour of the total TX (upload) label in basic mode.",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/ColorStr" "$ref": "#/definitions/ColorStr"
@ -831,6 +846,7 @@
"type": "object", "type": "object",
"properties": { "properties": {
"headers": { "headers": {
"description": "Text styling for table headers.",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/TextStyleConfig" "$ref": "#/definitions/TextStyleConfig"
@ -861,44 +877,52 @@
}, },
"TextStyleConfig": { "TextStyleConfig": {
"description": "A style for text.", "description": "A style for text.",
"type": "object", "anyOf": [
"properties": { {
"bg_color": { "$ref": "#/definitions/ColorStr"
"description": "A built-in ANSI colour, RGB hex, or RGB colour code.",
"anyOf": [
{
"$ref": "#/definitions/ColorStr"
},
{
"type": "null"
}
]
}, },
"bold": { {
"description": "Whether to make this text bolded or not. If not set, will default to built-in defaults.", "type": "object",
"type": [ "properties": {
"boolean", "bg_color": {
"null" "description": "A built-in ANSI colour, RGB hex, or RGB colour code.",
] "anyOf": [
}, {
"color": { "$ref": "#/definitions/ColorStr"
"description": "A built-in ANSI colour, RGB hex, or RGB colour code.", },
"anyOf": [ {
{ "type": "null"
"$ref": "#/definitions/ColorStr" }
]
}, },
{ "bold": {
"type": "null" "description": "Whether to make this text bolded or not. If not set, will default to built-in defaults.",
"type": [
"boolean",
"null"
]
},
"color": {
"description": "A built-in ANSI colour, RGB hex, or RGB colour code.",
"anyOf": [
{
"$ref": "#/definitions/ColorStr"
},
{
"type": "null"
}
]
} }
] }
} }
} ]
}, },
"WidgetStyle": { "WidgetStyle": {
"description": "General styling for generic widgets.", "description": "General styling for generic widgets.",
"type": "object", "type": "object",
"properties": { "properties": {
"border": { "border_color": {
"description": "The colour of the widgets' borders.",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/ColorStr" "$ref": "#/definitions/ColorStr"
@ -909,6 +933,7 @@
] ]
}, },
"disabled_text": { "disabled_text": {
"description": "Text styling for text when representing something that is disabled.",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/TextStyleConfig" "$ref": "#/definitions/TextStyleConfig"
@ -918,7 +943,8 @@
} }
] ]
}, },
"selected_border": { "selected_border_color": {
"description": "The colour of a widget's borders when the widget is selected.",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/ColorStr" "$ref": "#/definitions/ColorStr"
@ -929,6 +955,7 @@
] ]
}, },
"selected_text": { "selected_text": {
"description": "Text styling for text when representing something that is selected.",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/TextStyleConfig" "$ref": "#/definitions/TextStyleConfig"
@ -939,6 +966,7 @@
] ]
}, },
"text": { "text": {
"description": "Text styling for text in general.",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/TextStyleConfig" "$ref": "#/definitions/TextStyleConfig"
@ -949,6 +977,7 @@
] ]
}, },
"widget_title": { "widget_title": {
"description": "Text styling for a widget's title.",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/TextStyleConfig" "$ref": "#/definitions/TextStyleConfig"

View File

@ -411,22 +411,22 @@ pub const CONFIG_TEXT: &str = r#"# This is a default config file for bottom. Al
#cpu_core_colors = ["light magenta", "light yellow", "light cyan", "light green", "light blue", "cyan", "green", "blue"] #cpu_core_colors = ["light magenta", "light yellow", "light cyan", "light green", "light blue", "cyan", "green", "blue"]
#[styles.memory] #[styles.memory]
#ram = "light magenta" #ram_color = "light magenta"
#cache = "light red" #cache_color = "light red"
#swap = "light yellow" #swap_color = "light yellow"
#arc = "light cyan" #arc_color = "light cyan"
#gpus = ["light blue", "light red", "cyan", "green", "blue", "red"] #gpu_colors = ["light blue", "light red", "cyan", "green", "blue", "red"]
#[styles.network] #[styles.network]
#rx = "light magenta" #rx_color = "light magenta"
#tx = "light yellow" #tx_color = "light yellow"
#rx_total = "light cyan" #rx_total_color = "light cyan"
#tx_total = "light green" #tx_total_color = "light green"
#[styles.battery] #[styles.battery]
#high_battery = "green" #high_battery_color = "green"
#medium_battery = "yellow" #medium_battery_color = "yellow"
#low_battery = "red" #low_battery_color = "red"
#[styles.tables] #[styles.tables]
#headers = {color = "light blue"} #headers = {color = "light blue"}
@ -436,8 +436,8 @@ pub const CONFIG_TEXT: &str = r#"# This is a default config file for bottom. Al
#legend_text = {color = "gray"} #legend_text = {color = "gray"}
#[styles.widgets] #[styles.widgets]
#border = "gray" #border_color = "gray"
#selected_border = "light blue" #selected_border_color = "light blue"
#widget_title = {color = "gray"} #widget_title = {color = "gray"}
#text = {color = "gray"} #text = {color = "gray"}
#selected_text = {color = "black", bg_color = "light blue"} #selected_text = {color = "black", bg_color = "light blue"}

View File

@ -32,20 +32,24 @@ use super::Config;
pub(crate) struct ColorStr(Cow<'static, str>); pub(crate) struct ColorStr(Cow<'static, str>);
/// A style for text. /// A style for text.
#[derive(Clone, Debug, Default, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(untagged)]
#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))]
pub(crate) struct TextStyleConfig { pub(crate) enum TextStyleConfig {
/// A built-in ANSI colour, RGB hex, or RGB colour code. Colour(ColorStr),
#[serde(alias = "colour")] TextStyle {
pub(crate) color: Option<ColorStr>, /// A built-in ANSI colour, RGB hex, or RGB colour code.
#[serde(alias = "colour")]
color: Option<ColorStr>,
/// A built-in ANSI colour, RGB hex, or RGB colour code. /// A built-in ANSI colour, RGB hex, or RGB colour code.
#[serde(alias = "bg_colour")] #[serde(alias = "bg_colour")]
pub(crate) bg_color: Option<ColorStr>, bg_color: Option<ColorStr>,
/// Whether to make this text bolded or not. If not set, /// Whether to make this text bolded or not. If not set,
/// will default to built-in defaults. /// will default to built-in defaults.
pub(crate) bold: Option<bool>, bold: Option<bool>,
},
} }
/// Style-related configs. /// Style-related configs.
@ -161,28 +165,28 @@ impl ColourPalette {
set_colour_list!(self.cpu_colour_styles, config.cpu, cpu_core_colors); set_colour_list!(self.cpu_colour_styles, config.cpu, cpu_core_colors);
// Memory // Memory
set_colour!(self.ram_style, config.memory, ram); set_colour!(self.ram_style, config.memory, ram_color);
set_colour!(self.swap_style, config.memory, swap); set_colour!(self.swap_style, config.memory, swap_color);
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
set_colour!(self.cache_style, config.memory, cache); set_colour!(self.cache_style, config.memory, cache_color);
#[cfg(feature = "zfs")] #[cfg(feature = "zfs")]
set_colour!(self.arc_style, config.memory, arc); set_colour!(self.arc_style, config.memory, arc_color);
#[cfg(feature = "gpu")] #[cfg(feature = "gpu")]
set_colour_list!(self.gpu_colours, config.memory, gpus); set_colour_list!(self.gpu_colours, config.memory, gpu_colors);
// Network // Network
set_colour!(self.rx_style, config.network, rx); set_colour!(self.rx_style, config.network, rx_color);
set_colour!(self.tx_style, config.network, tx); set_colour!(self.tx_style, config.network, tx_color);
set_colour!(self.total_rx_style, config.network, rx_total); set_colour!(self.total_rx_style, config.network, rx_total_color);
set_colour!(self.total_tx_style, config.network, tx_total); set_colour!(self.total_tx_style, config.network, tx_total_color);
// Battery // Battery
set_colour!(self.high_battery, config.battery, high_battery); set_colour!(self.high_battery, config.battery, high_battery_color);
set_colour!(self.medium_battery, config.battery, medium_battery); set_colour!(self.medium_battery, config.battery, medium_battery_color);
set_colour!(self.low_battery, config.battery, low_battery); set_colour!(self.low_battery, config.battery, low_battery_color);
// Tables // Tables
set_style!(self.table_header_style, config.tables, headers); set_style!(self.table_header_style, config.tables, headers);
@ -198,11 +202,11 @@ impl ColourPalette {
set_style!(self.disabled_text_style, config.widgets, disabled_text); set_style!(self.disabled_text_style, config.widgets, disabled_text);
// Widget borders // Widget borders
set_colour!(self.border_style, config.widgets, border); set_colour!(self.border_style, config.widgets, border_color);
set_colour!( set_colour!(
self.highlighted_border_style, self.highlighted_border_style,
config.widgets, config.widgets,
selected_border selected_border_color
); );
Ok(()) Ok(())

View File

@ -6,7 +6,15 @@ use super::ColorStr;
#[derive(Clone, Debug, Default, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))]
pub(crate) struct BatteryStyle { pub(crate) struct BatteryStyle {
pub(crate) high_battery: Option<ColorStr>, /// The colour of the battery widget bar when the battery is over 50%.
pub(crate) medium_battery: Option<ColorStr>, #[serde(alias = "high_battery_colour")]
pub(crate) low_battery: Option<ColorStr>, pub(crate) high_battery_color: Option<ColorStr>,
/// The colour of the battery widget bar when the battery between 10% to 50%.
#[serde(alias = "medium_battery_colour")]
pub(crate) medium_battery_color: Option<ColorStr>,
/// The colour of the battery widget bar when the battery is under 10%.
#[serde(alias = "low_battery_colour")]
pub(crate) low_battery_color: Option<ColorStr>,
} }

View File

@ -6,13 +6,15 @@ use super::ColorStr;
#[derive(Clone, Debug, Default, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))]
pub(crate) struct CpuStyle { pub(crate) struct CpuStyle {
// TODO: Should I change the name of these? /// The colour of the "All" CPU label.
#[serde(alias = "all_entry_colour")] #[serde(alias = "all_entry_colour")]
pub(crate) all_entry_color: Option<ColorStr>, pub(crate) all_entry_color: Option<ColorStr>,
/// The colour of the average CPU label and graph line.
#[serde(alias = "avg_entry_colour")] #[serde(alias = "avg_entry_colour")]
pub(crate) avg_entry_color: Option<ColorStr>, pub(crate) avg_entry_color: Option<ColorStr>,
/// Colour of each CPU threads' label and graph line. Read in order.
#[serde(alias = "cpu_core_colours")] #[serde(alias = "cpu_core_colours")]
pub(crate) cpu_core_colors: Option<Vec<ColorStr>>, pub(crate) cpu_core_colors: Option<Vec<ColorStr>>,
} }

View File

@ -6,8 +6,10 @@ use super::{ColorStr, TextStyleConfig};
#[derive(Clone, Debug, Default, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))]
pub(crate) struct GraphStyle { pub(crate) struct GraphStyle {
/// The general colour of the parts of the graph.
#[serde(alias = "graph_colour")] #[serde(alias = "graph_colour")]
pub(crate) graph_color: Option<ColorStr>, pub(crate) graph_color: Option<ColorStr>,
/// Text styling for graph's legend text.
pub(crate) legend_text: Option<TextStyleConfig>, pub(crate) legend_text: Option<TextStyleConfig>,
} }

View File

@ -1,15 +1,30 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::ColorStr; use super::ColorStr;
// TODO: Maybe I should swap the alias and the field name since internally I use u.
/// Styling specific to the memory widget. /// Styling specific to the memory widget.
#[derive(Clone, Debug, Default, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))]
pub(crate) struct MemoryStyle { pub(crate) struct MemoryStyle {
pub(crate) ram: Option<ColorStr>, /// The colour of the RAM label and graph line.
#[serde(alias = "ram_colour")]
pub(crate) ram_color: Option<ColorStr>,
/// The colour of the cache label and graph line. Does not do anything on Windows.
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
pub(crate) cache: Option<ColorStr>, #[serde(alias = "cache_colour")]
pub(crate) swap: Option<ColorStr>, pub(crate) cache_color: Option<ColorStr>,
pub(crate) arc: Option<ColorStr>,
pub(crate) gpus: Option<Vec<ColorStr>>, /// The colour of the swap label and graph line.
#[serde(alias = "swap_colour")]
pub(crate) swap_color: Option<ColorStr>,
/// The colour of the ARC label and graph line.
#[serde(alias = "arc_colour")]
pub(crate) arc_color: Option<ColorStr>,
/// Colour of each GPU's memory label and graph line. Read in order.
#[serde(alias = "gpu_colours")]
pub(crate) gpu_colors: Option<Vec<ColorStr>>,
} }

View File

@ -6,14 +6,19 @@ use super::ColorStr;
#[derive(Clone, Debug, Default, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))]
pub(crate) struct NetworkStyle { pub(crate) struct NetworkStyle {
pub(crate) rx: Option<ColorStr>, /// The colour of the RX (download) label and graph line.
pub(crate) tx: Option<ColorStr>, #[serde(alias = "rx_colour")]
pub(crate) rx_color: Option<ColorStr>,
/// Set the colour of the "rx total" text. This only affects /// The colour of the TX (upload) label and graph line.
/// basic mode. #[serde(alias = "tx_colour")]
pub(crate) rx_total: Option<ColorStr>, pub(crate) tx_color: Option<ColorStr>,
/// Set the colour of the "tx total" text. This only affects /// he colour of the total RX (download) label in basic mode.
/// basic mode. #[serde(alias = "rx_total_colour")]
pub(crate) tx_total: Option<ColorStr>, pub(crate) rx_total_color: Option<ColorStr>,
/// The colour of the total TX (upload) label in basic mode.
#[serde(alias = "tx_total_colour")]
pub(crate) tx_total_color: Option<ColorStr>,
} }

View File

@ -6,5 +6,6 @@ use super::TextStyleConfig;
#[derive(Clone, Debug, Default, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))]
pub(crate) struct TableStyle { pub(crate) struct TableStyle {
/// Text styling for table headers.
pub(crate) headers: Option<TextStyleConfig>, pub(crate) headers: Option<TextStyleConfig>,
} }

View File

@ -1,5 +1,5 @@
use concat_string::concat_string; use concat_string::concat_string;
use tui::style::{Color, Style}; use tui::style::Color;
use unicode_segmentation::UnicodeSegmentation; use unicode_segmentation::UnicodeSegmentation;
/// Convert a hex string to a colour. /// Convert a hex string to a colour.
@ -53,10 +53,6 @@ pub fn str_to_colour(input_val: &str) -> Result<Color, String> {
} }
} }
pub(super) fn str_to_fg(input_val: &str) -> Result<Style, String> {
Ok(Style::default().fg(str_to_colour(input_val)?))
}
fn convert_rgb_to_color(rgb_str: &str) -> Result<Color, String> { fn convert_rgb_to_color(rgb_str: &str) -> Result<Color, String> {
let rgb_list = rgb_str.split(',').collect::<Vec<&str>>(); let rgb_list = rgb_str.split(',').collect::<Vec<&str>>();
if rgb_list.len() != 3 { if rgb_list.len() != 3 {
@ -136,18 +132,55 @@ macro_rules! opt {
macro_rules! set_style { macro_rules! set_style {
($palette_field:expr, $config_location:expr, $field:tt) => { ($palette_field:expr, $config_location:expr, $field:tt) => {
if let Some(style) = &(opt!($config_location.as_ref()?.$field.as_ref())) { if let Some(style) = &(opt!($config_location.as_ref()?.$field.as_ref())) {
if let Some(colour) = &style.color { match &style {
$palette_field = crate::options::config::style::utils::str_to_fg(&colour.0) TextStyleConfig::Colour(colour) => {
.map_err(|err| match stringify!($config_location).split_once(".") { $palette_field = $palette_field.fg(
Some((_, loc)) => OptionError::config(format!( crate::options::config::style::utils::str_to_colour(&colour.0)
"Please update 'styles.{loc}.{}' in your config file. {err}", .map_err(|err| match stringify!($config_location).split_once(".") {
stringify!($field) Some((_, loc)) => crate::options::OptionError::config(format!(
)), "Please update 'styles.{loc}.{}' in your config file. {err}",
None => OptionError::config(format!( stringify!($field)
"Please update 'styles.{}' in your config file. {err}", )),
stringify!($field) None => crate::options::OptionError::config(format!(
)), "Please update 'styles.{}' in your config file. {err}",
})?; stringify!($field)
)),
})?
);
}
TextStyleConfig::TextStyle {color, bg_color, bold: _} => {
if let Some(fg) = &color {
$palette_field = $palette_field.fg(
crate::options::config::style::utils::str_to_colour(&fg.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)
)),
})?
);
}
if let Some(bg) = &bg_color {
$palette_field = $palette_field.bg(
crate::options::config::style::utils::str_to_colour(&bg.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)
)),
})?
);
}
}
} }
} }
}; };
@ -156,19 +189,20 @@ macro_rules! set_style {
macro_rules! set_colour { macro_rules! set_colour {
($palette_field:expr, $config_location:expr, $field:tt) => { ($palette_field:expr, $config_location:expr, $field:tt) => {
if let Some(colour) = &(opt!($config_location.as_ref()?.$field.as_ref())) { if let Some(colour) = &(opt!($config_location.as_ref()?.$field.as_ref())) {
$palette_field = $palette_field = $palette_field.fg(
crate::options::config::style::utils::str_to_fg(&colour.0).map_err(|err| { crate::options::config::style::utils::str_to_colour(&colour.0).map_err(|err| {
match stringify!($config_location).split_once(".") { match stringify!($config_location).split_once(".") {
Some((_, loc)) => OptionError::config(format!( Some((_, loc)) => crate::options::OptionError::config(format!(
"Please update 'styles.{loc}.{}' in your config file. {err}", "Please update 'styles.{loc}.{}' in your config file. {err}",
stringify!($field) stringify!($field)
)), )),
None => OptionError::config(format!( None => crate::options::OptionError::config(format!(
"Please update 'styles.{}' in your config file. {err}", "Please update 'styles.{}' in your config file. {err}",
stringify!($field) stringify!($field)
)), )),
} }
})?; })?,
);
} }
}; };
} }
@ -178,14 +212,17 @@ macro_rules! set_colour_list {
if let Some(colour_list) = &(opt!($config_location.as_ref()?.$field.as_ref())) { if let Some(colour_list) = &(opt!($config_location.as_ref()?.$field.as_ref())) {
$palette_field = colour_list $palette_field = colour_list
.iter() .iter()
.map(|s| crate::options::config::style::utils::str_to_fg(&s.0)) .map(|s| {
Ok(Style::default()
.fg(crate::options::config::style::utils::str_to_colour(&s.0)?))
})
.collect::<Result<Vec<Style>, String>>() .collect::<Result<Vec<Style>, String>>()
.map_err(|err| match stringify!($config_location).split_once(".") { .map_err(|err| match stringify!($config_location).split_once(".") {
Some((_, loc)) => OptionError::config(format!( Some((_, loc)) => crate::options::OptionError::config(format!(
"Please update 'styles.{loc}.{}' in your config file. {err}", "Please update 'styles.{loc}.{}' in your config file. {err}",
stringify!($field) stringify!($field)
)), )),
None => OptionError::config(format!( None => crate::options::OptionError::config(format!(
"Please update 'styles.{}' in your config file. {err}", "Please update 'styles.{}' in your config file. {err}",
stringify!($field) stringify!($field)
)), )),
@ -199,6 +236,10 @@ pub(super) use {opt, set_colour, set_colour_list, set_style};
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use tui::style::Style;
use crate::options::config::style::{ColorStr, TextStyleConfig};
use super::*; use super::*;
#[test] #[test]
@ -351,4 +392,124 @@ mod test {
assert!(convert_rgb_to_color("1, -100000, 1").is_err()); assert!(convert_rgb_to_color("1, -100000, 1").is_err());
assert!(convert_rgb_to_color("1, -100000, 100000").is_err()); assert!(convert_rgb_to_color("1, -100000, 100000").is_err());
} }
struct DummyConfig {
inner: Option<InnerDummyConfig>,
}
struct InnerDummyConfig {
color_a: Option<ColorStr>,
color_b: Option<ColorStr>,
color_c: Option<ColorStr>,
color_d: Option<ColorStr>,
many_colors: Option<Vec<ColorStr>>,
text_a: Option<TextStyleConfig>,
text_b: Option<TextStyleConfig>,
text_c: Option<TextStyleConfig>,
text_d: Option<TextStyleConfig>,
text_e: Option<TextStyleConfig>,
}
impl Default for InnerDummyConfig {
fn default() -> Self {
Self {
color_a: None,
color_b: Some(ColorStr("red".into())),
color_c: Some(ColorStr("255, 255, 255".into())),
color_d: Some(ColorStr("#000000".into())),
many_colors: Some(vec![ColorStr("red".into()), ColorStr("blue".into())]),
text_a: Some(TextStyleConfig::Colour(ColorStr("green".into()))),
text_b: Some(TextStyleConfig::TextStyle {
color: None,
bg_color: None,
bold: None,
}),
text_c: Some(TextStyleConfig::TextStyle {
color: Some(ColorStr("magenta".into())),
bg_color: Some(ColorStr("255, 255, 255".into())),
bold: Some(false),
}),
text_d: Some(TextStyleConfig::TextStyle {
color: Some(ColorStr("#fff".into())),
bg_color: Some(ColorStr("1, 1, 1".into())),
bold: Some(true),
}),
text_e: None,
}
}
}
#[test]
fn test_set_colour() -> anyhow::Result<()> {
let mut s = Style::default().fg(Color::Black);
let dummy = DummyConfig {
inner: Some(InnerDummyConfig::default()),
};
set_colour!(s, &dummy.inner, color_a);
assert_eq!(s.fg.unwrap(), Color::Black);
assert_eq!(s.bg, None);
set_colour!(s, &dummy.inner, color_b);
assert_eq!(s.fg.unwrap(), Color::Red);
assert_eq!(s.bg, None);
set_colour!(s, &dummy.inner, color_c);
assert_eq!(s.fg.unwrap(), Color::Rgb(255, 255, 255));
assert_eq!(s.bg, None);
set_colour!(s, &dummy.inner, color_d);
assert_eq!(s.fg.unwrap(), Color::Rgb(0, 0, 0));
assert_eq!(s.bg, None);
Ok(())
}
#[test]
fn test_set_multi_colours() -> anyhow::Result<()> {
let mut s: Vec<Style> = vec![];
let dummy = DummyConfig {
inner: Some(InnerDummyConfig::default()),
};
set_colour_list!(s, &dummy.inner, many_colors);
assert_eq!(s.len(), 2);
assert_eq!(s[0].fg, Some(Color::Red));
assert_eq!(s[1].fg, Some(Color::Blue));
Ok(())
}
#[test]
fn test_set_style() -> anyhow::Result<()> {
let mut s = Style::default().fg(Color::Black);
let dummy = DummyConfig {
inner: Some(InnerDummyConfig::default()),
};
set_style!(s, &dummy.inner, text_e);
assert_eq!(s.fg.unwrap(), Color::Black);
assert_eq!(s.bg, None);
assert!(s.add_modifier.is_empty());
set_style!(s, &dummy.inner, text_a);
assert_eq!(s.fg.unwrap(), Color::Green);
assert_eq!(s.bg, None);
set_style!(s, &dummy.inner, text_b);
assert_eq!(s.fg.unwrap(), Color::Green);
assert_eq!(s.bg, None);
set_style!(s, &dummy.inner, text_c);
assert_eq!(s.fg.unwrap(), Color::Magenta);
assert_eq!(s.bg.unwrap(), Color::Rgb(255, 255, 255));
set_style!(s, &dummy.inner, text_d);
assert_eq!(s.fg.unwrap(), Color::Rgb(255, 255, 255));
assert_eq!(s.bg.unwrap(), Color::Rgb(1, 1, 1));
// TODO: Add this
// assert!(s.add_modifier.contains(Modifier::BOLD));
Ok(())
}
} }

View File

@ -6,11 +6,23 @@ use super::{ColorStr, TextStyleConfig};
#[derive(Clone, Debug, Default, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))]
pub(crate) struct WidgetStyle { pub(crate) struct WidgetStyle {
pub(crate) border: Option<ColorStr>, /// The colour of the widgets' borders.
pub(crate) selected_border: Option<ColorStr>, #[serde(alias = "border_colour")]
pub(crate) border_color: Option<ColorStr>,
/// The colour of a widget's borders when the widget is selected.
#[serde(alias = "selected_border_colour")]
pub(crate) selected_border_color: Option<ColorStr>,
/// Text styling for a widget's title.
pub(crate) widget_title: Option<TextStyleConfig>, pub(crate) widget_title: Option<TextStyleConfig>,
/// Text styling for text in general.
pub(crate) text: Option<TextStyleConfig>, pub(crate) text: Option<TextStyleConfig>,
/// Text styling for text when representing something that is selected.
pub(crate) selected_text: Option<TextStyleConfig>, pub(crate) selected_text: Option<TextStyleConfig>,
/// Text styling for text when representing something that is disabled.
pub(crate) disabled_text: Option<TextStyleConfig>, pub(crate) disabled_text: Option<TextStyleConfig>,
} }

View File

@ -1,6 +1,6 @@
# Test basic colours # Test basic colours
[styles.cpu] [styles.cpu]
all_entry_color="255, 50, 50" all_entry_color = "255, 50, 50"
# Test tables # Test tables
[styles.graphs.legend_text] [styles.graphs.legend_text]
@ -10,4 +10,10 @@ bold = false
# Test inline tables # Test inline tables
[styles.tables] [styles.tables]
headers = { color = "red", bg_color = "reset", bold = true } headers = { color = "red", bg_color = "black", bold = true }
# Test using normal colour where inline table can also work
[styles.widgets]
selected_text = "#fff"
disabled_text = "blue"
text = "255, 0, 255"

View File

@ -20,34 +20,34 @@ avg_entry_color = "red"
cpu_core_colors = ["light magenta", "light yellow", "light cyan", "light green", "light blue", "cyan", "green", "blue"] cpu_core_colors = ["light magenta", "light yellow", "light cyan", "light green", "light blue", "cyan", "green", "blue"]
[styles.memory] [styles.memory]
ram = "light magenta" ram_color = "light magenta"
cache = "light red" cache_color = "light red"
swap = "light yellow" swap_color = "light yellow"
arc = "light cyan" arc_color = "light cyan"
gpus = ["light blue", "light red", "cyan", "green", "blue", "red"] gpu_colors = ["light blue", "light red", "cyan", "green", "blue", "red"]
[styles.network] [styles.network]
rx = "light magenta" rx_color = "light magenta"
tx = "light yellow" tx_color = "light yellow"
rx_total = "light cyan" rx_total_color = "light cyan"
tx_total = "light green" tx_total_color = "light green"
[styles.battery] [styles.battery]
high_battery = "green" high_battery_color = "green"
medium_battery = "yellow" medium_battery_color = "yellow"
low_battery = "red" low_battery_color = "red"
[styles.tables] [styles.tables]
headers = {color = "light blue"} headers = { color = "light blue" }
[styles.graphs] [styles.graphs]
graph_color = "gray" graph_color = "gray"
legend_text = {color = "gray"} legend_text = { color = "gray" }
[styles.widgets] [styles.widgets]
border = "gray" border_color = "gray"
selected_border = "light blue" selected_border_color = "light blue"
widget_title = {color = "gray"} widget_title = { color = "gray" }
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" }