mirror of
https://github.com/ClementTsang/bottom
synced 2024-11-22 12:13:06 +00:00
feature: Add option to set a position of legend (#1430)
* Add option to set a position of legend * some small changes --------- Co-authored-by: ClementTsang <34804052+ClementTsang@users.noreply.github.com>
This commit is contained in:
parent
2ee0df1502
commit
a083ec00dd
12 changed files with 169 additions and 41 deletions
|
@ -58,6 +58,7 @@ see information on these options by running `btm -h`, or run `btm --help` to dis
|
|||
| ----------------------- | --------------------------------------------------------- |
|
||||
| `--enable_cache_memory` | Enable collecting and displaying cache and buffer memory. |
|
||||
| `--mem_as_value` | Defaults to showing process memory usage by value. |
|
||||
| `--memory_legend` | Where to place the legend for the memory widget. |
|
||||
|
||||
## Network Options
|
||||
|
||||
|
@ -66,6 +67,7 @@ see information on these options by running `btm -h`, or run `btm --help` to dis
|
|||
| `--network_use_binary_prefix` | Displays the network widget with binary prefixes. |
|
||||
| `--network_use_bytes` | Displays the network widget using bytes. |
|
||||
| `--network_use_log` | Displays the network widget with a log scale. |
|
||||
| `--network_legend` | Where to place the legend for the network widget. |
|
||||
| `--use_old_network_legend` | DEPRECATED - uses a separate network legend. |
|
||||
|
||||
## Battery Options
|
||||
|
|
|
@ -8,7 +8,7 @@ Most of the [command line flags](../command-line-options.md) have config file eq
|
|||
each time:
|
||||
|
||||
| Field | Type | Functionality |
|
||||
| ---------------------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
|
||||
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------- |
|
||||
| `hide_avg_cpu` | Boolean | Hides the average CPU usage. |
|
||||
| `dot_marker` | Boolean | Uses a dot marker for graphs. |
|
||||
| `left_legend` | Boolean | Puts the CPU chart legend to the left side. |
|
||||
|
@ -29,7 +29,7 @@ each time:
|
|||
| `default_widget_count` | Unsigned Int (represents which `default_widget_type`) | Sets the n'th selected widget type as the default. |
|
||||
| `disable_click` | Boolean | Disables mouse clicks. |
|
||||
| `color` | String (one of ["default", "default-light", "gruvbox", "gruvbox-light", "nord", "nord-light"]) | Use a color scheme, use --help for supported values. |
|
||||
| `enable_cache_memory` | Boolean | Enable collecting and displaying cache and buffer memory (not available on Windows). |
|
||||
| `enable_cache_memory` | Boolean | Enable cache and buffer memory stats (not available on Windows). |
|
||||
| `mem_as_value` | Boolean | Defaults to showing process memory usage by value. |
|
||||
| `tree` | Boolean | Defaults to showing the process widget in tree mode. |
|
||||
| `show_table_scroll_position` | Boolean | Shows the scroll position tracker in table widgets. |
|
||||
|
@ -42,3 +42,5 @@ each time:
|
|||
| `retention` | String (human readable time, such as "10m", "1h", etc.) | How much data is stored at once in terms of time. |
|
||||
| `unnormalized_cpu` | Boolean | Show process CPU% without normalizing over the number of cores. |
|
||||
| `expanded_on_startup` | Boolean | Expand the default widget upon starting the app. |
|
||||
| `memory_legend` | String (one of ["none", "top-left", "top", "top-right", "left", "right", "bottom-left", "bottom", "bottom-right"]) | Where to place the legend for the memory widget. |
|
||||
| `network_legend` | String (one of ["none", "top-left", "top", "top-right", "left", "right", "bottom-left", "bottom", "bottom-right"]) | Where to place the legend for the network widget. |
|
||||
|
|
|
@ -21,6 +21,7 @@ pub use states::*;
|
|||
use unicode_segmentation::{GraphemeCursor, UnicodeSegmentation};
|
||||
|
||||
use crate::{
|
||||
canvas::components::time_chart::LegendPosition,
|
||||
constants,
|
||||
data_collection::temperature,
|
||||
data_conversion::ConvertedData,
|
||||
|
@ -62,8 +63,10 @@ pub struct AppConfigFields {
|
|||
pub enable_cache_memory: bool,
|
||||
pub show_table_scroll_position: bool,
|
||||
pub is_advanced_kill: bool,
|
||||
pub memory_legend_position: Option<LegendPosition>,
|
||||
// TODO: Remove these, move network details state-side.
|
||||
pub network_unit_type: DataUnit,
|
||||
pub network_legend_position: Option<LegendPosition>,
|
||||
pub network_scale_type: AxisScaling,
|
||||
pub network_use_binary_prefix: bool,
|
||||
pub retention_ms: u64,
|
||||
|
|
|
@ -11,7 +11,9 @@ use tui::{
|
|||
};
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
|
||||
use super::time_chart::{Axis, Dataset, Point, TimeChart, DEFAULT_LEGEND_CONSTRAINTS};
|
||||
use super::time_chart::{
|
||||
Axis, Dataset, LegendPosition, Point, TimeChart, DEFAULT_LEGEND_CONSTRAINTS,
|
||||
};
|
||||
|
||||
/// Represents the data required by the [`TimeGraph`].
|
||||
pub struct GraphData<'a> {
|
||||
|
@ -48,6 +50,9 @@ pub struct TimeGraph<'a> {
|
|||
/// The title style.
|
||||
pub title_style: Style,
|
||||
|
||||
/// The legend position.
|
||||
pub legend_position: Option<LegendPosition>,
|
||||
|
||||
/// Any legend constraints.
|
||||
pub legend_constraints: Option<(Constraint, Constraint)>,
|
||||
|
||||
|
@ -142,6 +147,7 @@ impl<'a> TimeGraph<'a> {
|
|||
.y_axis(y_axis)
|
||||
.marker(self.marker)
|
||||
.legend_style(self.graph_style)
|
||||
.legend_position(self.legend_position)
|
||||
.hidden_legend_constraints(
|
||||
self.legend_constraints
|
||||
.unwrap_or(DEFAULT_LEGEND_CONSTRAINTS),
|
||||
|
@ -202,6 +208,7 @@ mod test {
|
|||
border_style: Style::default().fg(Color::Blue),
|
||||
is_expanded: false,
|
||||
title_style: Style::default().fg(Color::Cyan),
|
||||
legend_position: None,
|
||||
legend_constraints: None,
|
||||
marker: Marker::Braille,
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
mod canvas;
|
||||
mod points;
|
||||
|
||||
use std::cmp::max;
|
||||
use std::{cmp::max, str::FromStr};
|
||||
|
||||
use canvas::*;
|
||||
use tui::{
|
||||
|
@ -213,6 +213,27 @@ impl LegendPosition {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct ParseLegendPositionError;
|
||||
|
||||
impl FromStr for LegendPosition {
|
||||
type Err = ParseLegendPositionError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s.to_ascii_lowercase().as_str() {
|
||||
"top" => Ok(Self::Top),
|
||||
"top-left" => Ok(Self::TopLeft),
|
||||
"top-right" => Ok(Self::TopRight),
|
||||
"left" => Ok(Self::Left),
|
||||
"right" => Ok(Self::Right),
|
||||
"bottom-left" => Ok(Self::BottomLeft),
|
||||
"bottom" => Ok(Self::Bottom),
|
||||
"bottom-right" => Ok(Self::BottomRight),
|
||||
_ => Err(ParseLegendPositionError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A group of data points
|
||||
///
|
||||
/// This is the main element composing a [`TimeChart`].
|
||||
|
|
|
@ -233,6 +233,7 @@ impl Painter {
|
|||
title,
|
||||
is_expanded: app_state.is_expanded,
|
||||
title_style: self.colours.widget_title_style,
|
||||
legend_position: None,
|
||||
legend_constraints: None,
|
||||
marker,
|
||||
}
|
||||
|
|
|
@ -133,6 +133,7 @@ impl Painter {
|
|||
title: " Memory ".into(),
|
||||
is_expanded: app_state.is_expanded,
|
||||
title_style: self.colours.widget_title_style,
|
||||
legend_position: app_state.app_config_fields.memory_legend_position,
|
||||
legend_constraints: Some((Constraint::Ratio(3, 4), Constraint::Ratio(3, 4))),
|
||||
marker,
|
||||
}
|
||||
|
|
|
@ -162,6 +162,7 @@ impl Painter {
|
|||
title: " Network ".into(),
|
||||
is_expanded: app_state.is_expanded,
|
||||
title_style: self.colours.widget_title_style,
|
||||
legend_position: app_state.app_config_fields.network_legend_position,
|
||||
legend_constraints: Some(legend_constraints),
|
||||
marker,
|
||||
}
|
||||
|
|
|
@ -597,6 +597,10 @@ pub const CONFIG_TEXT: &str = r#"# This is a default config file for bottom. Al
|
|||
#enable_cache_memory = false
|
||||
# How much data is stored at once in terms of time.
|
||||
#retention = "10m"
|
||||
# Where to place the legend for the memory widget. One of "none", "top-left", "top", "top-right", "left", "right", "bottom-left", "bottom", "bottom-right".
|
||||
#memory_legend = "TopRight".
|
||||
# Where to place the legend for the network widget. One of "none", "top-left", "top", "top-right", "left", "right", "bottom-left", "bottom", "bottom-right".
|
||||
#network_legend = "TopRight".
|
||||
|
||||
# These are flags around the process widget.
|
||||
#[processes]
|
||||
|
|
|
@ -24,7 +24,7 @@ use starship_battery::Manager;
|
|||
use self::config::{layout::Row, IgnoreList, StringOrNum};
|
||||
use crate::{
|
||||
app::{filter::Filter, layout_manager::*, *},
|
||||
canvas::{styling::CanvasStyling, ColourScheme},
|
||||
canvas::{components::time_chart::LegendPosition, styling::CanvasStyling, ColourScheme},
|
||||
constants::*,
|
||||
data_collection::temperature::TemperatureType,
|
||||
utils::{
|
||||
|
@ -126,6 +126,9 @@ pub fn init_app(
|
|||
}
|
||||
};
|
||||
|
||||
let network_legend_position = get_network_legend(matches, config)?;
|
||||
let memory_legend_position = get_memory_legend(matches, config)?;
|
||||
|
||||
// TODO: Can probably just reuse the options struct.
|
||||
let app_config_fields = AppConfigFields {
|
||||
update_rate: get_update_rate(matches, config)
|
||||
|
@ -150,6 +153,8 @@ pub fn init_app(
|
|||
enable_cache_memory: get_enable_cache_memory(matches, config),
|
||||
show_table_scroll_position: is_flag_enabled!(show_table_scroll_position, matches, config),
|
||||
is_advanced_kill,
|
||||
memory_legend_position,
|
||||
network_legend_position,
|
||||
network_scale_type,
|
||||
network_unit_type,
|
||||
network_use_binary_prefix,
|
||||
|
@ -772,6 +777,48 @@ fn get_retention(matches: &ArgMatches, config: &Config) -> error::Result<u64> {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_network_legend(
|
||||
matches: &ArgMatches, config: &Config,
|
||||
) -> error::Result<Option<LegendPosition>> {
|
||||
let error =
|
||||
|_| BottomError::ConfigError("network_legend is set to an invalid value".to_string());
|
||||
if let Some(s) = matches.get_one::<String>("network_legend") {
|
||||
match s.to_ascii_lowercase().trim() {
|
||||
"none" => Ok(None),
|
||||
position => Ok(Some(position.parse::<LegendPosition>().map_err(error)?)),
|
||||
}
|
||||
} else if let Some(flags) = &config.flags {
|
||||
if let Some(legend) = &flags.network_legend {
|
||||
Ok(Some(legend.parse::<LegendPosition>().map_err(error)?))
|
||||
} else {
|
||||
Ok(Some(LegendPosition::default()))
|
||||
}
|
||||
} else {
|
||||
Ok(Some(LegendPosition::default()))
|
||||
}
|
||||
}
|
||||
|
||||
fn get_memory_legend(
|
||||
matches: &ArgMatches, config: &Config,
|
||||
) -> error::Result<Option<LegendPosition>> {
|
||||
let error =
|
||||
|_| BottomError::ConfigError("memory_legend is set to an invalid value".to_string());
|
||||
if let Some(s) = matches.get_one::<String>("memory_legend") {
|
||||
match s.to_ascii_lowercase().trim() {
|
||||
"none" => Ok(None),
|
||||
position => Ok(Some(position.parse::<LegendPosition>().map_err(error)?)),
|
||||
}
|
||||
} else if let Some(flags) = &config.flags {
|
||||
if let Some(legend) = &flags.memory_legend {
|
||||
Ok(Some(legend.parse::<LegendPosition>().map_err(error)?))
|
||||
} else {
|
||||
Ok(Some(LegendPosition::default()))
|
||||
}
|
||||
} else {
|
||||
Ok(Some(LegendPosition::default()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use clap::ArgMatches;
|
||||
|
|
|
@ -436,6 +436,24 @@ fn mem_args(cmd: Command) -> Command {
|
|||
to showing it by percentage.",
|
||||
);
|
||||
|
||||
let memory_legend = Arg::new("memory_legend")
|
||||
.long("memory_legend")
|
||||
.action(ArgAction::Set)
|
||||
.value_name("POSITION")
|
||||
.ignore_case(true)
|
||||
.help("Where to place the legend for the memory widget.")
|
||||
.value_parser([
|
||||
"none",
|
||||
"top-left",
|
||||
"top",
|
||||
"top-right",
|
||||
"left",
|
||||
"right",
|
||||
"bottom-left",
|
||||
"bottom",
|
||||
"bottom-right",
|
||||
]);
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
let enable_cache_memory = Arg::new("enable_cache_memory")
|
||||
|
@ -443,11 +461,11 @@ fn mem_args(cmd: Command) -> Command {
|
|||
.action(ArgAction::SetTrue)
|
||||
.help("Enable collecting and displaying cache and buffer memory.");
|
||||
|
||||
cmd.args(args![mem_as_value, enable_cache_memory])
|
||||
cmd.args(args![mem_as_value, memory_legend, enable_cache_memory])
|
||||
}
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
cmd.arg(mem_as_value)
|
||||
cmd.args(args![mem_as_value, memory_legend])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -464,6 +482,24 @@ fn network_args(cmd: Command) -> Command {
|
|||
display is not tested anymore and may be broken.",
|
||||
);
|
||||
|
||||
let network_legend = Arg::new("network_legend")
|
||||
.long("network_legend")
|
||||
.action(ArgAction::Set)
|
||||
.value_name("POSITION")
|
||||
.ignore_case(true)
|
||||
.help("Where to place the legend for the network widget.")
|
||||
.value_parser([
|
||||
"none",
|
||||
"top-left",
|
||||
"top",
|
||||
"top-right",
|
||||
"left",
|
||||
"right",
|
||||
"bottom-left",
|
||||
"bottom",
|
||||
"bottom-right",
|
||||
]);
|
||||
|
||||
let network_use_bytes = Arg::new("network_use_bytes")
|
||||
.long("network_use_bytes")
|
||||
.action(ArgAction::SetTrue)
|
||||
|
@ -487,6 +523,7 @@ fn network_args(cmd: Command) -> Command {
|
|||
|
||||
cmd.args(args![
|
||||
use_old_network_legend,
|
||||
network_legend,
|
||||
network_use_bytes,
|
||||
network_use_log,
|
||||
network_use_binary_prefix,
|
||||
|
|
|
@ -68,6 +68,8 @@ pub(crate) struct ConfigFlags {
|
|||
pub(crate) battery: Option<bool>,
|
||||
pub(crate) disable_click: Option<bool>,
|
||||
pub(crate) no_write: Option<bool>,
|
||||
pub(crate) network_legend: Option<String>,
|
||||
pub(crate) memory_legend: Option<String>,
|
||||
/// For built-in colour palettes.
|
||||
pub(crate) color: Option<String>,
|
||||
pub(crate) mem_as_value: Option<bool>,
|
||||
|
|
Loading…
Reference in a new issue