mirror of
https://github.com/ClementTsang/bottom.git
synced 2026-09-24 19:45:39 +00:00
feature: add more pipe gauge bar fill options (#2245)
Adds block and square character options for pipe gauge widgets. May still redesign this (maybe add option for a background), but this is fine for now.
This commit is contained in:
@@ -29,6 +29,7 @@ That said, these are more guidelines rather than hard rules, though the project
|
||||
### Features
|
||||
|
||||
- [#2239](https://github.com/ClementTsang/bottom/pull/2239): Initial Intel GPU support for Linux to get process GPU usage.
|
||||
- [#1434](https://github.com/ClementTsang/bottom/issues/1434): Support solid bars using block and square characters via `styles.widgets.bar_type`.
|
||||
|
||||
### Other
|
||||
|
||||
|
||||
@@ -187,13 +187,14 @@ These can be set under `[styles.graphs]`:
|
||||
|
||||
These can be set under `[styles.widgets]`:
|
||||
|
||||
| Config field | Details | Examples |
|
||||
| ------------------------ | -------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
|
||||
| `border_colour` | The colour of the widgets' borders | `border_colour = "white"` |
|
||||
| `selected_border_colour` | The colour of a widget's borders when the widget is selected | `selected_border_colour = "white"` |
|
||||
| `widget_title` | Text styling for a widget's title | `widget_title = { colour = "black", bg_colour = "blue", bold = true }` |
|
||||
| `bg_colour` | The background colour of the widgets | `bg_colour = "black"` |
|
||||
| `text` | Text styling for text in general | `text = { colour = "black", bg_colour = "blue", bold = true }` |
|
||||
| `selected_text` | Text styling for text when representing something that is selected | `selected_text = { colour = "black", bg_colour = "blue", bold = true }` |
|
||||
| `disabled_text` | Text styling for text when representing something that is disabled | `disabled_text = { colour = "black", bg_colour = "blue", bold = true }` |
|
||||
| `thread_text` | Text styling for text when representing process thread, only usable on Linux at the moment | `thread_text = { colour = "green", bg_colour = "blue", bold = true }` |
|
||||
| Config field | Details | Examples |
|
||||
| ------------------------ | ---------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
|
||||
| `border_colour` | The colour of the widgets' borders | `border_colour = "white"` |
|
||||
| `selected_border_colour` | The colour of a widget's borders when the widget is selected | `selected_border_colour = "white"` |
|
||||
| `widget_title` | Text styling for a widget's title | `widget_title = { colour = "black", bg_colour = "blue", bold = true }` |
|
||||
| `bg_colour` | The background colour of the widgets | `bg_colour = "black"` |
|
||||
| `text` | Text styling for text in general | `text = { colour = "black", bg_colour = "blue", bold = true }` |
|
||||
| `selected_text` | Text styling for text when representing something that is selected | `selected_text = { colour = "black", bg_colour = "blue", bold = true }` |
|
||||
| `disabled_text` | Text styling for text when representing something that is disabled | `disabled_text = { colour = "black", bg_colour = "blue", bold = true }` |
|
||||
| `thread_text` | Text styling for text when representing process thread, only usable on Linux at the moment | `thread_text = { colour = "green", bg_colour = "blue", bold = true }` |
|
||||
| `bar_type` | What to fill bar widgets with (e.g. basic CPU/memory); either `"pipe"` (default), `"block"`, or `"square"` | `bar_type = "block"` |
|
||||
|
||||
@@ -474,10 +474,12 @@
|
||||
#text = {colour = "gray"}
|
||||
#selected_text = {colour = "black", bg_colour = "light blue"}
|
||||
#disabled_text = {colour = "dark gray"}
|
||||
# Disabled by default
|
||||
# Disabled by default.
|
||||
#bg_colour = "black"
|
||||
# Only on Linux
|
||||
# Only supported on Linux.
|
||||
#thread_text = {colour = "green"}
|
||||
# One of "pipe", "block", or "square".
|
||||
#bar_type = "pipe"
|
||||
|
||||
# Layout - layouts follow a pattern like this:
|
||||
# [[row]] represents a row in the application.
|
||||
|
||||
+46
-15
@@ -268,7 +268,7 @@
|
||||
]
|
||||
},
|
||||
"include_unmounted": {
|
||||
"description": "Whether to include block devices that aren't currently mounted (currently Linux only). Defaults to false.",
|
||||
"description": "Whether to include block devices that aren't currently mounted\n(currently Linux only). Defaults to false.",
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
@@ -322,14 +322,14 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"include_unmounted": {
|
||||
"description": "Whether to include block devices that aren't currently mounted (currently Linux only). Defaults to false.",
|
||||
"description": "Whether to include block devices that aren't currently mounted\n(currently Linux only). Defaults to false.",
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"legend": {
|
||||
"description": "Whether to label legend entries by device name or mount point. Defaults to disk name.",
|
||||
"description": "Whether to label legend entries by device name or mount point. Defaults\nto disk name.",
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/$defs/DiskGraphLegend"
|
||||
@@ -812,7 +812,7 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cache_memory": {
|
||||
"description": "Whether to collect and display cache and buffer memory. Not available on Windows.",
|
||||
"description": "Whether to collect and display cache and buffer memory. Not available on\nWindows.",
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
@@ -931,14 +931,14 @@
|
||||
]
|
||||
},
|
||||
"start_zeroed": {
|
||||
"description": "Zeroes out the total network usage (\"All\") counters so it shows the total usage\nsince the app is started, rather than the total usage since boot.",
|
||||
"description": "Zeroes out the total network usage (\"All\") counters so it shows the\ntotal usage since the app is started, rather than the total usage\nsince boot.",
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"use_binary_prefix": {
|
||||
"description": "Displays the network widget with a binary prefix (e.g. kibibits) rather than a decimal\nprefix (e.g. kilobits). Defaults to decimal prefixes.",
|
||||
"description": "Displays the network widget with a binary prefix (e.g. kibibits) rather\nthan a decimal prefix (e.g. kilobits). Defaults to decimal prefixes.",
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
@@ -952,7 +952,7 @@
|
||||
]
|
||||
},
|
||||
"use_log": {
|
||||
"description": "Displays the network widget with a log scale. Defaults to a non-log scale.",
|
||||
"description": "Displays the network widget with a log scale. Defaults to a non-log\nscale.",
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
@@ -1101,14 +1101,14 @@
|
||||
}
|
||||
},
|
||||
"current_usage": {
|
||||
"description": "Calculates process CPU usage as a percentage of current usage rather than total usage.",
|
||||
"description": "Calculates process CPU usage as a percentage of current usage rather\nthan total usage.",
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"default_grouped": {
|
||||
"description": "Groups processes with the same name by default. No effect if `--tree` is set.",
|
||||
"description": "Groups processes with the same name by default. No effect if `--tree` is\nset.",
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
@@ -1140,7 +1140,7 @@
|
||||
]
|
||||
},
|
||||
"disable_advanced_kill": {
|
||||
"description": "Disable the advanced kill dialog and just show the basic one with no options.",
|
||||
"description": "Disable the advanced kill dialog and just show the basic one with no\noptions.",
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
@@ -1441,7 +1441,7 @@
|
||||
"default": null
|
||||
},
|
||||
"max_temp": {
|
||||
"description": "An upper temperature value for the graph; entries higher than this will be hidden. If not set,\nthere is no limit.\n\nIs in the configured temperature unit.",
|
||||
"description": "An upper temperature value for the graph; entries higher than this will\nbe hidden. If not set, there is no limit.\n\nIs in the configured temperature unit.",
|
||||
"type": [
|
||||
"number",
|
||||
"null"
|
||||
@@ -1538,19 +1538,50 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"WidgetBarType": {
|
||||
"description": "The type of character used to fill in bars, such as the ones used by the\nbasic CPU and memory widgets.",
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "Fill bars with pipe characters (`|`).",
|
||||
"type": "string",
|
||||
"const": "pipe"
|
||||
},
|
||||
{
|
||||
"description": "Fill bars with block characters (`█`, `▉`, etc.).",
|
||||
"type": "string",
|
||||
"const": "block"
|
||||
},
|
||||
{
|
||||
"description": "Fill bars with square characters (`■`).",
|
||||
"type": "string",
|
||||
"const": "square"
|
||||
}
|
||||
]
|
||||
},
|
||||
"WidgetBorderType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Default",
|
||||
"Rounded",
|
||||
"Double",
|
||||
"Thick"
|
||||
"default",
|
||||
"rounded",
|
||||
"double",
|
||||
"thick"
|
||||
]
|
||||
},
|
||||
"WidgetStyle": {
|
||||
"description": "General styling for generic widgets.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"bar_type": {
|
||||
"description": "What character to fill in bars with, such as the ones used by the basic\nCPU and memory widgets.",
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/$defs/WidgetBarType"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"bg_colour": {
|
||||
"description": "Background colour for widgets.",
|
||||
"anyOf": [
|
||||
|
||||
@@ -44,6 +44,8 @@ macro_rules! generate_column_schemas {
|
||||
}
|
||||
|
||||
fn generate_schema(schema_options: SchemaOptions) -> anyhow::Result<()> {
|
||||
// TODO: remove newlines in descriptions?
|
||||
|
||||
let mut schema = schemars::schema_for!(config::Config);
|
||||
{
|
||||
// TODO: Maybe make this case insensitive? See https://stackoverflow.com/a/68639341
|
||||
|
||||
@@ -2,6 +2,7 @@ use ratatui::{
|
||||
buffer::Buffer,
|
||||
layout::Rect,
|
||||
style::Style,
|
||||
symbols,
|
||||
text::Line,
|
||||
widgets::{Block, Widget},
|
||||
};
|
||||
@@ -16,7 +17,41 @@ pub enum LabelLimit {
|
||||
StartLabel,
|
||||
}
|
||||
|
||||
/// A widget to measure something, using pipe characters ('|') as a unit.
|
||||
/// What bar character type to use.
|
||||
#[derive(Debug, Clone, Default, Copy)]
|
||||
pub enum BarType {
|
||||
#[default]
|
||||
/// The pipe character (`|`)
|
||||
Pipe,
|
||||
/// Block characters (`█`, `▉`, etc.)
|
||||
Block,
|
||||
/// Square characters (`■`)
|
||||
Square,
|
||||
}
|
||||
|
||||
impl BarType {
|
||||
#[inline]
|
||||
fn is_block(&self) -> bool {
|
||||
matches!(self, BarType::Block)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_unicode_block(frac: f64) -> &'static str {
|
||||
match (frac * 8.0).round() as u16 {
|
||||
0 => " ",
|
||||
1 => symbols::block::ONE_EIGHTH,
|
||||
2 => symbols::block::ONE_QUARTER,
|
||||
3 => symbols::block::THREE_EIGHTHS,
|
||||
4 => symbols::block::HALF,
|
||||
5 => symbols::block::FIVE_EIGHTHS,
|
||||
6 => symbols::block::THREE_QUARTERS,
|
||||
7 => symbols::block::SEVEN_EIGHTHS,
|
||||
8 => symbols::block::FULL,
|
||||
_ => unreachable!("this case should never occur"),
|
||||
}
|
||||
}
|
||||
|
||||
/// A widget to measure something, using pipe characters ('|') or horizontal bar characters as a unit.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PipeGauge<'a> {
|
||||
block: Option<Block<'a>>,
|
||||
@@ -26,6 +61,7 @@ pub struct PipeGauge<'a> {
|
||||
label_style: Style,
|
||||
gauge_style: Style,
|
||||
hide_parts: LabelLimit,
|
||||
bar_type: BarType,
|
||||
}
|
||||
|
||||
impl Default for PipeGauge<'_> {
|
||||
@@ -38,6 +74,7 @@ impl Default for PipeGauge<'_> {
|
||||
label_style: Style::default(),
|
||||
gauge_style: Style::default(),
|
||||
hide_parts: LabelLimit::default(),
|
||||
bar_type: BarType::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,6 +126,12 @@ impl<'a> PipeGauge<'a> {
|
||||
self.hide_parts = hide_parts;
|
||||
self
|
||||
}
|
||||
|
||||
/// What type of bar character to use.
|
||||
pub fn bar_type(mut self, bar_type: BarType) -> Self {
|
||||
self.bar_type = bar_type;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for PipeGauge<'_> {
|
||||
@@ -184,11 +227,11 @@ impl Widget for PipeGauge<'_> {
|
||||
);
|
||||
}
|
||||
LabelLimit::Auto(_) | LabelLimit::None => {
|
||||
// FIXME: "[" and "]" don't look that great with block bars.
|
||||
let (start, _) = buf.set_line(col, row, &Line::from("["), gauge_area.width);
|
||||
if start >= gauge_area.right() {
|
||||
return;
|
||||
}
|
||||
|
||||
let (end, _) = buf.set_line(
|
||||
(gauge_area.x + gauge_area.width).saturating_sub(1),
|
||||
row,
|
||||
@@ -196,22 +239,40 @@ impl Widget for PipeGauge<'_> {
|
||||
gauge_area.width,
|
||||
);
|
||||
|
||||
let pipe_end = end.saturating_sub(1).min(
|
||||
start + (f64::from(end.saturating_sub(start)) * self.ratio).floor() as u16,
|
||||
);
|
||||
let bar_end = end.saturating_sub(1);
|
||||
let filled_width = f64::from(bar_end.saturating_sub(start)) * self.ratio;
|
||||
let pipe_end = bar_end.min(start + filled_width.floor() as u16);
|
||||
|
||||
let symbol = match self.bar_type {
|
||||
BarType::Pipe => "|",
|
||||
BarType::Block => symbols::block::FULL,
|
||||
BarType::Square => "■",
|
||||
};
|
||||
|
||||
let bar_style = Style {
|
||||
fg: self.gauge_style.fg,
|
||||
bg: None,
|
||||
add_modifier: self.gauge_style.add_modifier,
|
||||
sub_modifier: self.gauge_style.sub_modifier,
|
||||
underline_color: None,
|
||||
};
|
||||
|
||||
for col in start..pipe_end {
|
||||
if let Some(cell) = buf.cell_mut((col, row)) {
|
||||
cell.set_symbol("|").set_style(Style {
|
||||
fg: self.gauge_style.fg,
|
||||
bg: None,
|
||||
add_modifier: self.gauge_style.add_modifier,
|
||||
sub_modifier: self.gauge_style.sub_modifier,
|
||||
underline_color: None,
|
||||
});
|
||||
cell.set_symbol(symbol).set_style(bar_style);
|
||||
}
|
||||
}
|
||||
|
||||
// Unlike pipes, blocks can also show the leftover fraction of a cell.
|
||||
// Based on what Ratatui does!
|
||||
if self.bar_type.is_block()
|
||||
&& pipe_end < bar_end
|
||||
&& let Some(cell) = buf.cell_mut((pipe_end, row))
|
||||
{
|
||||
cell.set_symbol(get_unicode_block(filled_width.fract()))
|
||||
.set_style(bar_style);
|
||||
}
|
||||
|
||||
if (end_label.width() as u16) < end.saturating_sub(start) {
|
||||
let gauge_end = gauge_area
|
||||
.right()
|
||||
@@ -223,3 +284,107 @@ impl Widget for PipeGauge<'_> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_get_unicode_block() {
|
||||
// Test exact values.
|
||||
assert_eq!(get_unicode_block(0.0), " ");
|
||||
assert_eq!(get_unicode_block(0.125), symbols::block::ONE_EIGHTH);
|
||||
assert_eq!(get_unicode_block(0.25), symbols::block::ONE_QUARTER);
|
||||
assert_eq!(get_unicode_block(0.375), symbols::block::THREE_EIGHTHS);
|
||||
assert_eq!(get_unicode_block(0.5), symbols::block::HALF);
|
||||
assert_eq!(get_unicode_block(0.625), symbols::block::FIVE_EIGHTHS);
|
||||
assert_eq!(get_unicode_block(0.75), symbols::block::THREE_QUARTERS);
|
||||
assert_eq!(get_unicode_block(0.875), symbols::block::SEVEN_EIGHTHS);
|
||||
assert_eq!(get_unicode_block(1.0), symbols::block::FULL);
|
||||
|
||||
// Test rounding.
|
||||
assert_eq!(get_unicode_block(0.05), " ");
|
||||
assert_eq!(get_unicode_block(0.1), symbols::block::ONE_EIGHTH);
|
||||
assert_eq!(get_unicode_block(0.3), symbols::block::ONE_QUARTER);
|
||||
assert_eq!(get_unicode_block(0.4), symbols::block::THREE_EIGHTHS);
|
||||
assert_eq!(get_unicode_block(0.55), symbols::block::HALF);
|
||||
assert_eq!(get_unicode_block(0.6), symbols::block::FIVE_EIGHTHS);
|
||||
assert_eq!(get_unicode_block(0.8), symbols::block::THREE_QUARTERS);
|
||||
assert_eq!(get_unicode_block(0.9), symbols::block::SEVEN_EIGHTHS);
|
||||
assert_eq!(get_unicode_block(0.99), symbols::block::FULL);
|
||||
}
|
||||
|
||||
/// Create a [`PipeGauge`] and return what it would have rendered.
|
||||
fn render_gauge(
|
||||
ratio: f64, bar_type: BarType, start_label: Option<&str>, inner_label: Option<&str>,
|
||||
) -> String {
|
||||
const WIDTH: u16 = 12;
|
||||
|
||||
let area = Rect::new(0, 0, WIDTH, 1);
|
||||
let mut buf = Buffer::empty(area);
|
||||
let mut gauge = PipeGauge::default().ratio(ratio).bar_type(bar_type);
|
||||
|
||||
if let Some(start_label) = start_label {
|
||||
gauge = gauge.start_label(start_label.to_owned());
|
||||
}
|
||||
|
||||
if let Some(inner_label) = inner_label {
|
||||
gauge = gauge.inner_label(inner_label.to_owned());
|
||||
}
|
||||
|
||||
gauge.render(area, &mut buf);
|
||||
|
||||
(0..WIDTH).map(|x| buf[(x, 0)].symbol()).collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pipe_bars() {
|
||||
assert_eq!(render_gauge(0.0, BarType::Pipe, None, None), "[ ]");
|
||||
assert_eq!(render_gauge(0.5, BarType::Pipe, None, None), "[||||| ]");
|
||||
assert_eq!(
|
||||
render_gauge(0.95, BarType::Pipe, None, None),
|
||||
"[||||||||| ]"
|
||||
);
|
||||
assert_eq!(render_gauge(1.0, BarType::Pipe, None, None), "[||||||||||]");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_solid_bars() {
|
||||
assert_eq!(
|
||||
render_gauge(0.0, BarType::Block, None, None),
|
||||
"[ ]"
|
||||
);
|
||||
assert_eq!(
|
||||
render_gauge(0.5, BarType::Block, None, None),
|
||||
"[█████ ]"
|
||||
);
|
||||
assert_eq!(
|
||||
render_gauge(0.55, BarType::Block, None, None),
|
||||
"[█████▌ ]"
|
||||
);
|
||||
assert_eq!(
|
||||
render_gauge(0.9, BarType::Block, None, None),
|
||||
"[█████████ ]"
|
||||
);
|
||||
assert_eq!(
|
||||
render_gauge(1.0, BarType::Block, None, None),
|
||||
"[██████████]"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_labelled_bars() {
|
||||
assert_eq!(
|
||||
render_gauge(0.5, BarType::Pipe, Some("CPU"), Some(" 50%")),
|
||||
"CPU[||| 50%]"
|
||||
);
|
||||
assert_eq!(
|
||||
render_gauge(0.5, BarType::Block, Some("CPU"), Some(" 50%")),
|
||||
"CPU[███ 50%]"
|
||||
);
|
||||
assert_eq!(
|
||||
render_gauge(1.0, BarType::Block, Some("CPU"), Some("100%")),
|
||||
"CPU[███100%]"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,7 +214,8 @@ impl Painter {
|
||||
|
||||
let block_inner = block.inner(margined_draw_loc);
|
||||
|
||||
// Draw bar
|
||||
// Draw bar.
|
||||
// TODO: Switch to pipe_gauge.
|
||||
f.render_widget(
|
||||
Table::new(battery_charge_rows, [Constraint::Percentage(100)])
|
||||
.block(block.clone())
|
||||
|
||||
@@ -71,7 +71,8 @@ impl Painter {
|
||||
.label_style(style)
|
||||
.inner_label(inner)
|
||||
.start_label(outer)
|
||||
.ratio(ratio.into()),
|
||||
.ratio(ratio.into())
|
||||
.bar_type(self.styles.bar_type),
|
||||
avg_loc,
|
||||
);
|
||||
avg_row_count += 1;
|
||||
@@ -139,7 +140,8 @@ impl Painter {
|
||||
.inner_label(inner_label)
|
||||
.start_label(start_label)
|
||||
.ratio(ratio.into())
|
||||
.hide_parts(hide_parts),
|
||||
.hide_parts(hide_parts)
|
||||
.bar_type(self.styles.bar_type),
|
||||
*row,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -81,7 +81,8 @@ impl Painter {
|
||||
.start_label("RAM")
|
||||
.inner_label(ram_label)
|
||||
.label_style(self.styles.ram_style)
|
||||
.gauge_style(self.styles.ram_style),
|
||||
.gauge_style(self.styles.ram_style)
|
||||
.bar_type(self.styles.bar_type),
|
||||
);
|
||||
|
||||
if let Some(swap_harvest) = &data.swap_harvest {
|
||||
@@ -94,7 +95,8 @@ impl Painter {
|
||||
.start_label("SWP")
|
||||
.inner_label(swap_label)
|
||||
.label_style(self.styles.swap_style)
|
||||
.gauge_style(self.styles.swap_style),
|
||||
.gauge_style(self.styles.swap_style)
|
||||
.bar_type(self.styles.bar_type),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -111,7 +113,8 @@ impl Painter {
|
||||
.start_label("CHE")
|
||||
.inner_label(cache_fraction_label)
|
||||
.label_style(self.styles.cache_style)
|
||||
.gauge_style(self.styles.cache_style),
|
||||
.gauge_style(self.styles.cache_style)
|
||||
.bar_type(self.styles.bar_type),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -129,7 +132,8 @@ impl Painter {
|
||||
.start_label("ARC")
|
||||
.inner_label(arc_fraction_label)
|
||||
.label_style(self.styles.arc_style)
|
||||
.gauge_style(self.styles.arc_style),
|
||||
.gauge_style(self.styles.arc_style)
|
||||
.bar_type(self.styles.bar_type),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -160,7 +164,8 @@ impl Painter {
|
||||
.start_label("GPU")
|
||||
.inner_label(label)
|
||||
.label_style(style)
|
||||
.gauge_style(style),
|
||||
.gauge_style(style)
|
||||
.bar_type(self.styles.bar_type),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-2
@@ -723,10 +723,12 @@ pub(crate) const CONFIG_TEXT: &str = r#"# This is a default config file for bott
|
||||
#text = {colour = "gray"}
|
||||
#selected_text = {colour = "black", bg_colour = "light blue"}
|
||||
#disabled_text = {colour = "dark gray"}
|
||||
# Disabled by default
|
||||
# Disabled by default.
|
||||
#bg_colour = "black"
|
||||
# Only on Linux
|
||||
# Only supported on Linux.
|
||||
#thread_text = {colour = "green"}
|
||||
# One of "pipe", "block", or "square".
|
||||
#bar_type = "pipe"
|
||||
|
||||
# Layout - layouts follow a pattern like this:
|
||||
# [[row]] represents a row in the application.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
//! Config options around styling.
|
||||
|
||||
mod bars;
|
||||
mod battery;
|
||||
mod borders;
|
||||
mod cpu;
|
||||
@@ -29,8 +30,9 @@ use utils::{opt, set_colour, set_colour_list, set_style};
|
||||
use widgets::WidgetStyle;
|
||||
|
||||
use super::Config;
|
||||
use crate::options::{
|
||||
OptionError, OptionResult, args::BottomArgs, config::style::utils::set_bg_colour,
|
||||
use crate::{
|
||||
canvas::components::pipe_gauge::BarType,
|
||||
options::{OptionError, OptionResult, args::BottomArgs, config::style::utils::set_bg_colour},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
@@ -143,6 +145,7 @@ pub struct Styles {
|
||||
#[cfg(target_os = "linux")]
|
||||
pub(crate) thread_text_style: Style,
|
||||
pub(crate) border_type: BorderType,
|
||||
pub(crate) bar_type: BarType,
|
||||
}
|
||||
|
||||
impl Default for Styles {
|
||||
@@ -261,10 +264,14 @@ impl Styles {
|
||||
selected_border_colour
|
||||
);
|
||||
|
||||
if let Some(widgets) = &config.widgets
|
||||
&& let Some(widget_borders) = widgets.widget_border_type
|
||||
{
|
||||
self.border_type = widget_borders.into();
|
||||
if let Some(widgets) = &config.widgets {
|
||||
if let Some(widget_borders) = widgets.widget_border_type {
|
||||
self.border_type = widget_borders.into();
|
||||
}
|
||||
|
||||
if let Some(bar_type) = widgets.bar_type {
|
||||
self.bar_type = bar_type.into();
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::canvas::components::pipe_gauge::BarType;
|
||||
|
||||
/// The type of character used to fill in bars, such as the ones used by the
|
||||
/// basic CPU and memory widgets.
|
||||
#[derive(Default, Clone, Copy, Debug, Serialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))]
|
||||
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||
pub(crate) enum WidgetBarType {
|
||||
/// Fill bars with pipe characters (`|`).
|
||||
#[default]
|
||||
Pipe,
|
||||
/// Fill bars with block characters (`█`, `▉`, etc.).
|
||||
Block,
|
||||
/// Fill bars with square characters (`■`).
|
||||
Square,
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for WidgetBarType {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let value = String::deserialize(deserializer)?.to_lowercase();
|
||||
match value.as_str() {
|
||||
"pipe" => Ok(WidgetBarType::Pipe),
|
||||
"block" => Ok(WidgetBarType::Block),
|
||||
"square" => Ok(WidgetBarType::Square),
|
||||
_ => Err(serde::de::Error::custom("doesn't match any bar type")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WidgetBarType> for BarType {
|
||||
fn from(value: WidgetBarType) -> Self {
|
||||
match value {
|
||||
WidgetBarType::Pipe => BarType::Pipe,
|
||||
WidgetBarType::Block => BarType::Block,
|
||||
WidgetBarType::Square => BarType::Square,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::WidgetBarType;
|
||||
use crate::options::config::style::widgets::WidgetStyle;
|
||||
|
||||
fn parse(value: &str) -> anyhow::Result<Option<WidgetBarType>> {
|
||||
let style = toml_edit::de::from_str::<WidgetStyle>(&format!("bar_type = {value}"))?;
|
||||
|
||||
Ok(style.bar_type)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn valid_bar_types() {
|
||||
assert_eq!(parse("\"pipe\"").unwrap(), Some(WidgetBarType::Pipe));
|
||||
assert_eq!(parse("\"block\"").unwrap(), Some(WidgetBarType::Block));
|
||||
assert_eq!(parse("\"square\"").unwrap(), Some(WidgetBarType::Square));
|
||||
|
||||
// Casing shouldn't matter.
|
||||
assert_eq!(parse("\"PIPE\"").unwrap(), Some(WidgetBarType::Pipe));
|
||||
assert_eq!(parse("\"BLOCK\"").unwrap(), Some(WidgetBarType::Block));
|
||||
assert_eq!(parse("\"SQUARE\"").unwrap(), Some(WidgetBarType::Square));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_bar_types() {
|
||||
assert!(parse("\"bar\"").is_err());
|
||||
assert!(parse("\"\"").is_err());
|
||||
assert!(parse("true").is_err());
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ use ratatui::widgets::BorderType;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Default, Clone, Copy, Debug, Serialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))]
|
||||
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||
pub(crate) enum WidgetBorderType {
|
||||
|
||||
@@ -4,7 +4,7 @@ use ratatui::{
|
||||
};
|
||||
|
||||
use super::colour;
|
||||
use crate::options::config::style::Styles;
|
||||
use crate::{canvas::components::pipe_gauge::BarType, options::config::style::Styles};
|
||||
|
||||
impl Styles {
|
||||
pub(crate) fn default_palette() -> Self {
|
||||
@@ -75,6 +75,7 @@ impl Styles {
|
||||
invalid_query_style: colour!(Color::Red),
|
||||
disabled_text_style: colour!(Color::DarkGray),
|
||||
border_type: BorderType::Plain,
|
||||
bar_type: BarType::default(),
|
||||
#[cfg(target_os = "linux")]
|
||||
thread_text_style: colour!(Color::Green),
|
||||
}
|
||||
|
||||
@@ -4,7 +4,10 @@ use ratatui::{
|
||||
};
|
||||
|
||||
use super::{colour, hex};
|
||||
use crate::options::config::style::{Styles, themes::hex_colour};
|
||||
use crate::{
|
||||
canvas::components::pipe_gauge::BarType,
|
||||
options::config::style::{Styles, themes::hex_colour},
|
||||
};
|
||||
|
||||
impl Styles {
|
||||
pub(crate) fn gruvbox_palette() -> Self {
|
||||
@@ -75,6 +78,7 @@ impl Styles {
|
||||
invalid_query_style: colour!(Color::Red),
|
||||
disabled_text_style: hex!("#665c54"),
|
||||
border_type: BorderType::Plain,
|
||||
bar_type: BarType::default(),
|
||||
#[cfg(target_os = "linux")]
|
||||
thread_text_style: hex!("#458588"),
|
||||
}
|
||||
@@ -154,6 +158,7 @@ impl Styles {
|
||||
invalid_query_style: colour!(Color::Red),
|
||||
disabled_text_style: hex!("#d5c4a1"),
|
||||
border_type: BorderType::Plain,
|
||||
bar_type: BarType::default(),
|
||||
#[cfg(target_os = "linux")]
|
||||
thread_text_style: hex!("#458588"),
|
||||
}
|
||||
|
||||
@@ -4,7 +4,10 @@ use ratatui::{
|
||||
};
|
||||
|
||||
use super::{colour, hex};
|
||||
use crate::options::config::style::{Styles, themes::hex_colour};
|
||||
use crate::{
|
||||
canvas::components::pipe_gauge::BarType,
|
||||
options::config::style::{Styles, themes::hex_colour},
|
||||
};
|
||||
|
||||
impl Styles {
|
||||
pub(crate) fn nord_palette() -> Self {
|
||||
@@ -63,6 +66,7 @@ impl Styles {
|
||||
invalid_query_style: colour!(Color::Red),
|
||||
disabled_text_style: hex!("#4c566a"),
|
||||
border_type: BorderType::Plain,
|
||||
bar_type: BarType::default(),
|
||||
#[cfg(target_os = "linux")]
|
||||
thread_text_style: hex!("#a3be8c"),
|
||||
}
|
||||
@@ -124,6 +128,7 @@ impl Styles {
|
||||
invalid_query_style: colour!(Color::Red),
|
||||
disabled_text_style: hex!("#d8dee9"),
|
||||
border_type: BorderType::Plain,
|
||||
bar_type: BarType::default(),
|
||||
#[cfg(target_os = "linux")]
|
||||
thread_text_style: hex!("#a3be8c"),
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::{ColourStr, TextStyleConfig, borders::WidgetBorderType};
|
||||
use super::{ColourStr, TextStyleConfig, bars::WidgetBarType, borders::WidgetBorderType};
|
||||
|
||||
/// General styling for generic widgets.
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||
@@ -37,4 +37,8 @@ pub(crate) struct WidgetStyle {
|
||||
/// Background colour for widgets.
|
||||
#[serde(alias = "bg_color")]
|
||||
pub(crate) bg_colour: Option<ColourStr>,
|
||||
|
||||
/// What character to fill in bars with, such as the ones used by the basic
|
||||
/// CPU and memory widgets.
|
||||
pub(crate) bar_type: Option<WidgetBarType>,
|
||||
}
|
||||
|
||||
@@ -64,3 +64,4 @@ text = { colour = "gray" }
|
||||
selected_text = { colour = "black", bg_colour = "light blue" }
|
||||
disabled_text = { colour = "dark gray" }
|
||||
bg_colour = "black"
|
||||
bar_type = "block"
|
||||
|
||||
Reference in New Issue
Block a user