mirror of
https://github.com/ClementTsang/bottom
synced 2024-11-10 22:54:21 +00:00
refactor: switch to pipe gauge implementation for basic cpu + mem (#829)
* refactor: switch to pipe gauge implementation for basic cpu + mem * fix incorrect new basic cpu chunking scheme, revert to old one
This commit is contained in:
parent
436dadb683
commit
b6a75db1b4
5 changed files with 349 additions and 222 deletions
|
@ -1,8 +1,9 @@
|
|||
use std::cmp::min;
|
||||
|
||||
use crate::{
|
||||
app::App,
|
||||
canvas::{drawing_utils::*, Painter},
|
||||
app::{data_harvester::cpu::CpuDataType, App},
|
||||
canvas::Painter,
|
||||
components::tui_widget::pipe_gauge::{LabelLimit, PipeGauge},
|
||||
constants::*,
|
||||
data_conversion::CpuWidgetData,
|
||||
};
|
||||
|
@ -11,11 +12,11 @@ use tui::{
|
|||
backend::Backend,
|
||||
layout::{Constraint, Direction, Layout, Rect},
|
||||
terminal::Frame,
|
||||
text::{Span, Spans},
|
||||
widgets::{Block, Paragraph},
|
||||
widgets::Block,
|
||||
};
|
||||
|
||||
impl Painter {
|
||||
/// Inspired by htop.
|
||||
pub fn draw_basic_cpu<B: Backend>(
|
||||
&self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64,
|
||||
) {
|
||||
|
@ -42,148 +43,84 @@ impl Painter {
|
|||
);
|
||||
}
|
||||
|
||||
let num_cpus = cpu_data.len();
|
||||
let show_avg_cpu = app_state.app_config_fields.show_average_cpu;
|
||||
|
||||
if draw_loc.height > 0 {
|
||||
let remaining_height = usize::from(draw_loc.height);
|
||||
const REQUIRED_COLUMNS: usize = 4;
|
||||
|
||||
let chunk_vec =
|
||||
let col_constraints =
|
||||
vec![Constraint::Percentage((100 / REQUIRED_COLUMNS) as u16); REQUIRED_COLUMNS];
|
||||
let chunks = Layout::default()
|
||||
.constraints(chunk_vec)
|
||||
let columns = Layout::default()
|
||||
.constraints(col_constraints)
|
||||
.direction(Direction::Horizontal)
|
||||
.split(draw_loc);
|
||||
|
||||
const CPU_NAME_SPACE: usize = 3;
|
||||
const BAR_BOUND_SPACE: usize = 2;
|
||||
const PERCENTAGE_SPACE: usize = 4;
|
||||
const MARGIN_SPACE: usize = 2;
|
||||
let mut gauge_info = cpu_data.iter().map(|cpu| match cpu {
|
||||
CpuWidgetData::All => unreachable!(),
|
||||
CpuWidgetData::Entry {
|
||||
data_type,
|
||||
data: _,
|
||||
last_entry,
|
||||
} => {
|
||||
let (outer, style) = match data_type {
|
||||
CpuDataType::Avg => ("AVG".to_string(), self.colours.avg_colour_style),
|
||||
CpuDataType::Cpu(index) => (
|
||||
format!("{index:<3}",),
|
||||
self.colours.cpu_colour_styles
|
||||
[index % self.colours.cpu_colour_styles.len()],
|
||||
),
|
||||
};
|
||||
let inner = format!("{:>3.0}%", last_entry.round());
|
||||
let ratio = last_entry / 100.0;
|
||||
|
||||
const COMBINED_SPACING: usize =
|
||||
CPU_NAME_SPACE + BAR_BOUND_SPACE + PERCENTAGE_SPACE + MARGIN_SPACE;
|
||||
const REDUCED_SPACING: usize = CPU_NAME_SPACE + PERCENTAGE_SPACE + MARGIN_SPACE;
|
||||
let chunk_width: usize = chunks[0].width.into();
|
||||
(outer, inner, ratio, style)
|
||||
}
|
||||
});
|
||||
|
||||
// Inspired by htop.
|
||||
// We do +4 as if it's too few bars in the bar length, it's kinda pointless.
|
||||
let cpu_bars = if chunk_width >= COMBINED_SPACING + 4 {
|
||||
let bar_length = chunk_width - COMBINED_SPACING;
|
||||
cpu_data
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(index, cpu)| match &cpu {
|
||||
CpuWidgetData::All => None,
|
||||
CpuWidgetData::Entry {
|
||||
data_type: _,
|
||||
data: _,
|
||||
last_entry,
|
||||
} => {
|
||||
let num_bars = calculate_basic_use_bars(*last_entry, bar_length);
|
||||
Some(format!(
|
||||
"{:3}[{}{}{:3.0}%]",
|
||||
if app_state.app_config_fields.show_average_cpu {
|
||||
if index == 0 {
|
||||
"AVG".to_string()
|
||||
} else {
|
||||
(index - 1).to_string()
|
||||
}
|
||||
} else {
|
||||
index.to_string()
|
||||
},
|
||||
"|".repeat(num_bars),
|
||||
" ".repeat(bar_length - num_bars),
|
||||
last_entry.round(),
|
||||
))
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
} else if chunk_width >= REDUCED_SPACING {
|
||||
cpu_data
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(index, cpu)| match &cpu {
|
||||
CpuWidgetData::All => None,
|
||||
CpuWidgetData::Entry {
|
||||
data_type: _,
|
||||
data: _,
|
||||
last_entry,
|
||||
} => Some(format!(
|
||||
"{:3} {:3.0}%",
|
||||
if app_state.app_config_fields.show_average_cpu {
|
||||
if index == 0 {
|
||||
"AVG".to_string()
|
||||
} else {
|
||||
(index - 1).to_string()
|
||||
}
|
||||
} else {
|
||||
index.to_string()
|
||||
},
|
||||
last_entry.round(),
|
||||
)),
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
} else {
|
||||
cpu_data
|
||||
.iter()
|
||||
.filter_map(|cpu| match &cpu {
|
||||
CpuWidgetData::All => None,
|
||||
CpuWidgetData::Entry {
|
||||
data_type: _,
|
||||
data: _,
|
||||
last_entry,
|
||||
} => Some(format!("{:3.0}%", last_entry.round())),
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
// Very ugly way to sync the gauge limit across all gauges.
|
||||
let hide_parts = columns
|
||||
.get(0)
|
||||
.map(|col| {
|
||||
if col.width >= 12 {
|
||||
LabelLimit::None
|
||||
} else if col.width >= 10 {
|
||||
LabelLimit::Bars
|
||||
} else {
|
||||
LabelLimit::StartLabel
|
||||
}
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
let mut row_counter = num_cpus;
|
||||
let mut start_index = 0;
|
||||
for (itx, chunk) in chunks.iter().enumerate() {
|
||||
// Explicitly check... don't want an accidental DBZ or underflow, this ensures
|
||||
// to_divide is > 0
|
||||
let num_entries = cpu_data.len();
|
||||
let mut row_counter = num_entries;
|
||||
for (itx, column) in columns.into_iter().enumerate() {
|
||||
if REQUIRED_COLUMNS > itx {
|
||||
let to_divide = REQUIRED_COLUMNS - itx;
|
||||
let how_many_cpus = min(
|
||||
let num_taken = min(
|
||||
remaining_height,
|
||||
(row_counter / to_divide)
|
||||
+ (if row_counter % to_divide == 0 { 0 } else { 1 }),
|
||||
);
|
||||
row_counter -= how_many_cpus;
|
||||
let end_index = min(start_index + how_many_cpus, num_cpus);
|
||||
row_counter -= num_taken;
|
||||
let chunk = (&mut gauge_info).take(num_taken);
|
||||
|
||||
let cpu_column = (start_index..end_index)
|
||||
.map(|itx| {
|
||||
Spans::from(Span {
|
||||
content: (&cpu_bars[itx]).into(),
|
||||
style: if show_avg_cpu {
|
||||
if itx == 0 {
|
||||
self.colours.avg_colour_style
|
||||
} else {
|
||||
self.colours.cpu_colour_styles
|
||||
[(itx - 1) % self.colours.cpu_colour_styles.len()]
|
||||
}
|
||||
} else {
|
||||
self.colours.cpu_colour_styles
|
||||
[itx % self.colours.cpu_colour_styles.len()]
|
||||
},
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
start_index += how_many_cpus;
|
||||
|
||||
let margined_loc = Layout::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.constraints([Constraint::Percentage(100)])
|
||||
let rows = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints(vec![Constraint::Length(1); remaining_height])
|
||||
.horizontal_margin(1)
|
||||
.split(*chunk)[0];
|
||||
.split(column);
|
||||
|
||||
f.render_widget(
|
||||
Paragraph::new(cpu_column).block(Block::default()),
|
||||
margined_loc,
|
||||
);
|
||||
for ((start_label, inner_label, ratio, style), row) in chunk.zip(rows) {
|
||||
f.render_widget(
|
||||
PipeGauge::default()
|
||||
.gauge_style(style)
|
||||
.label_style(style)
|
||||
.inner_label(inner_label)
|
||||
.start_label(start_label)
|
||||
.ratio(ratio)
|
||||
.hide_parts(hide_parts),
|
||||
row,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
use crate::{
|
||||
app::App,
|
||||
canvas::{drawing_utils::*, Painter},
|
||||
constants::*,
|
||||
app::App, canvas::Painter, components::tui_widget::pipe_gauge::PipeGauge, constants::*,
|
||||
};
|
||||
|
||||
use tui::{
|
||||
backend::Backend,
|
||||
layout::{Constraint, Layout, Rect},
|
||||
layout::{Constraint, Direction, Layout, Rect},
|
||||
terminal::Frame,
|
||||
text::Span,
|
||||
text::Spans,
|
||||
widgets::{Block, Paragraph},
|
||||
widgets::Block,
|
||||
};
|
||||
|
||||
impl Painter {
|
||||
|
@ -21,7 +17,18 @@ impl Painter {
|
|||
let swap_data: &[(f64, f64)] = &app_state.converted_data.swap_data;
|
||||
|
||||
let margined_loc = Layout::default()
|
||||
.constraints([Constraint::Percentage(100)])
|
||||
.constraints({
|
||||
#[cfg(feature = "zfs")]
|
||||
{
|
||||
[Constraint::Length(1); 3]
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "zfs"))]
|
||||
{
|
||||
[Constraint::Length(1); 2]
|
||||
}
|
||||
})
|
||||
.direction(Direction::Vertical)
|
||||
.horizontal_margin(1)
|
||||
.split(draw_loc);
|
||||
|
||||
|
@ -34,118 +41,78 @@ impl Painter {
|
|||
);
|
||||
}
|
||||
|
||||
let ram_use_percentage = if let Some(mem) = mem_data.last() {
|
||||
mem.1
|
||||
let ram_ratio = if let Some(mem) = mem_data.last() {
|
||||
mem.1 / 100.0
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
let swap_use_percentage = if let Some(swap) = swap_data.last() {
|
||||
swap.1
|
||||
let swap_ratio = if let Some(swap) = swap_data.last() {
|
||||
swap.1 / 100.0
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
const EMPTY_MEMORY_FRAC_STRING: &str = "0.0B/0.0B";
|
||||
|
||||
let trimmed_memory_frac =
|
||||
if let Some((_label_percent, label_frac)) = &app_state.converted_data.mem_labels {
|
||||
let memory_fraction_label =
|
||||
if let Some((_, label_frac)) = &app_state.converted_data.mem_labels {
|
||||
label_frac.trim()
|
||||
} else {
|
||||
EMPTY_MEMORY_FRAC_STRING
|
||||
};
|
||||
|
||||
let trimmed_swap_frac =
|
||||
if let Some((_label_percent, label_frac)) = &app_state.converted_data.swap_labels {
|
||||
let swap_fraction_label =
|
||||
if let Some((_, label_frac)) = &app_state.converted_data.swap_labels {
|
||||
label_frac.trim()
|
||||
} else {
|
||||
EMPTY_MEMORY_FRAC_STRING
|
||||
};
|
||||
|
||||
// +7 due to 3 + 2 + 2 columns for the name & space + bar bounds + margin spacing
|
||||
// Then + length of fraction
|
||||
let ram_bar_length =
|
||||
usize::from(draw_loc.width.saturating_sub(7)).saturating_sub(trimmed_memory_frac.len());
|
||||
let swap_bar_length =
|
||||
usize::from(draw_loc.width.saturating_sub(7)).saturating_sub(trimmed_swap_frac.len());
|
||||
f.render_widget(
|
||||
PipeGauge::default()
|
||||
.ratio(ram_ratio)
|
||||
.start_label("RAM")
|
||||
.inner_label(memory_fraction_label)
|
||||
.label_style(self.colours.ram_style)
|
||||
.gauge_style(self.colours.ram_style),
|
||||
margined_loc[0],
|
||||
);
|
||||
|
||||
let num_bars_ram = calculate_basic_use_bars(ram_use_percentage, ram_bar_length);
|
||||
let num_bars_swap = calculate_basic_use_bars(swap_use_percentage, swap_bar_length);
|
||||
// TODO: Use different styling for the frac.
|
||||
let mem_label = if app_state.basic_mode_use_percent {
|
||||
format!(
|
||||
"RAM[{}{}{:3.0}%]\n",
|
||||
"|".repeat(num_bars_ram),
|
||||
" ".repeat(ram_bar_length - num_bars_ram + trimmed_memory_frac.len() - 4),
|
||||
ram_use_percentage.round()
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"RAM[{}{}{}]\n",
|
||||
"|".repeat(num_bars_ram),
|
||||
" ".repeat(ram_bar_length - num_bars_ram),
|
||||
trimmed_memory_frac
|
||||
)
|
||||
};
|
||||
let swap_label = if app_state.basic_mode_use_percent {
|
||||
format!(
|
||||
"SWP[{}{}{:3.0}%]",
|
||||
"|".repeat(num_bars_swap),
|
||||
" ".repeat(swap_bar_length - num_bars_swap + trimmed_swap_frac.len() - 4),
|
||||
swap_use_percentage.round()
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"SWP[{}{}{}]",
|
||||
"|".repeat(num_bars_swap),
|
||||
" ".repeat(swap_bar_length - num_bars_swap),
|
||||
trimmed_swap_frac
|
||||
)
|
||||
};
|
||||
f.render_widget(
|
||||
PipeGauge::default()
|
||||
.ratio(swap_ratio)
|
||||
.start_label("SWP")
|
||||
.inner_label(swap_fraction_label)
|
||||
.label_style(self.colours.swap_style)
|
||||
.gauge_style(self.colours.swap_style),
|
||||
margined_loc[1],
|
||||
);
|
||||
|
||||
let mem_text = vec![
|
||||
Spans::from(Span::styled(mem_label, self.colours.ram_style)),
|
||||
Spans::from(Span::styled(swap_label, self.colours.swap_style)),
|
||||
#[cfg(feature = "zfs")]
|
||||
{
|
||||
let arc_data: &[(f64, f64)] = &app_state.converted_data.arc_data;
|
||||
let arc_use_percentage = if let Some(arc) = arc_data.last() {
|
||||
arc.1
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
let trimmed_arc_frac = if let Some((_label_percent, label_frac)) =
|
||||
&app_state.converted_data.arc_labels
|
||||
{
|
||||
#[cfg(feature = "zfs")]
|
||||
{
|
||||
let arc_data: &[(f64, f64)] = &app_state.converted_data.arc_data;
|
||||
let arc_ratio = if let Some(arc) = arc_data.last() {
|
||||
arc.1 / 100.0
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
let arc_fraction_label =
|
||||
if let Some((_, label_frac)) = &app_state.converted_data.arc_labels {
|
||||
label_frac.trim()
|
||||
} else {
|
||||
EMPTY_MEMORY_FRAC_STRING
|
||||
};
|
||||
let arc_bar_length = usize::from(draw_loc.width.saturating_sub(7))
|
||||
.saturating_sub(trimmed_arc_frac.len());
|
||||
let num_bars_arc = calculate_basic_use_bars(arc_use_percentage, arc_bar_length);
|
||||
let arc_label = if app_state.basic_mode_use_percent {
|
||||
format!(
|
||||
"ARC[{}{}{:3.0}%]",
|
||||
"|".repeat(num_bars_arc),
|
||||
" ".repeat(arc_bar_length - num_bars_arc + trimmed_arc_frac.len() - 4),
|
||||
arc_use_percentage.round()
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"ARC[{}{}{}]",
|
||||
"|".repeat(num_bars_arc),
|
||||
" ".repeat(arc_bar_length - num_bars_arc),
|
||||
trimmed_arc_frac
|
||||
)
|
||||
};
|
||||
Spans::from(Span::styled(arc_label, self.colours.arc_style))
|
||||
},
|
||||
];
|
||||
|
||||
f.render_widget(
|
||||
Paragraph::new(mem_text).block(Block::default()),
|
||||
margined_loc[0],
|
||||
);
|
||||
f.render_widget(
|
||||
PipeGauge::default()
|
||||
.ratio(arc_ratio)
|
||||
.start_label("ARC")
|
||||
.inner_label(arc_fraction_label)
|
||||
.label_style(self.colours.arc_style)
|
||||
.gauge_style(self.colours.arc_style),
|
||||
margined_loc[2],
|
||||
);
|
||||
}
|
||||
|
||||
// Update draw loc in widget map
|
||||
if app_state.should_get_widget_bounds() {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
mod tui_widget;
|
||||
|
||||
pub mod data_table;
|
||||
pub mod time_graph;
|
||||
pub mod tui_widget;
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
pub mod pipe_gauge;
|
||||
pub mod time_chart;
|
||||
|
|
223
src/components/tui_widget/pipe_gauge.rs
Normal file
223
src/components/tui_widget/pipe_gauge.rs
Normal file
|
@ -0,0 +1,223 @@
|
|||
use tui::{
|
||||
buffer::Buffer,
|
||||
layout::Rect,
|
||||
style::Style,
|
||||
text::Spans,
|
||||
widgets::{Block, Widget},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum LabelLimit {
|
||||
None,
|
||||
Auto(u16),
|
||||
Bars,
|
||||
StartLabel,
|
||||
}
|
||||
|
||||
impl Default for LabelLimit {
|
||||
fn default() -> Self {
|
||||
Self::None
|
||||
}
|
||||
}
|
||||
|
||||
/// A widget to measure something, using pipe characters ('|') as a unit.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PipeGauge<'a> {
|
||||
block: Option<Block<'a>>,
|
||||
ratio: f64,
|
||||
start_label: Option<Spans<'a>>,
|
||||
inner_label: Option<Spans<'a>>,
|
||||
label_style: Style,
|
||||
gauge_style: Style,
|
||||
hide_parts: LabelLimit,
|
||||
}
|
||||
|
||||
impl<'a> Default for PipeGauge<'a> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
block: None,
|
||||
ratio: 0.0,
|
||||
start_label: None,
|
||||
inner_label: None,
|
||||
label_style: Style::default(),
|
||||
gauge_style: Style::default(),
|
||||
hide_parts: LabelLimit::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PipeGauge<'a> {
|
||||
/// The ratio, a value from 0.0 to 1.0 (any other greater or less will be clamped)
|
||||
/// represents the portion of the pipe gauge to fill.
|
||||
///
|
||||
/// Note: passing in NaN will potentially cause problems.
|
||||
pub fn ratio(mut self, ratio: f64) -> Self {
|
||||
self.ratio = ratio.clamp(0.0, 1.0);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
/// The label displayed before the bar.
|
||||
pub fn start_label<T>(mut self, start_label: T) -> Self
|
||||
where
|
||||
T: Into<Spans<'a>>,
|
||||
{
|
||||
self.start_label = Some(start_label.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// The label displayed inside the bar.
|
||||
pub fn inner_label<T>(mut self, inner_label: T) -> Self
|
||||
where
|
||||
T: Into<Spans<'a>>,
|
||||
{
|
||||
self.inner_label = Some(inner_label.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// The style of the labels.
|
||||
pub fn label_style(mut self, label_style: Style) -> Self {
|
||||
self.label_style = label_style;
|
||||
self
|
||||
}
|
||||
|
||||
/// The style of the gauge itself.
|
||||
pub fn gauge_style(mut self, style: Style) -> Self {
|
||||
self.gauge_style = style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Whether to hide parts of the gauge/label if the inner label wouldn't fit.
|
||||
pub fn hide_parts(mut self, hide_parts: LabelLimit) -> Self {
|
||||
self.hide_parts = hide_parts;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Widget for PipeGauge<'a> {
|
||||
fn render(mut self, area: Rect, buf: &mut Buffer) {
|
||||
buf.set_style(area, self.label_style);
|
||||
let gauge_area = match self.block.take() {
|
||||
Some(b) => {
|
||||
let inner_area = b.inner(area);
|
||||
b.render(area, buf);
|
||||
inner_area
|
||||
}
|
||||
None => area,
|
||||
};
|
||||
|
||||
if gauge_area.height < 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
let (col, row) = {
|
||||
let inner_label_width = self
|
||||
.inner_label
|
||||
.as_ref()
|
||||
.map(|l| l.width())
|
||||
.unwrap_or_default();
|
||||
|
||||
let start_label_width = self
|
||||
.start_label
|
||||
.as_ref()
|
||||
.map(|l| l.width())
|
||||
.unwrap_or_default();
|
||||
|
||||
match self.hide_parts {
|
||||
LabelLimit::StartLabel => {
|
||||
let inner_label = self.inner_label.unwrap_or_else(|| Spans::from(""));
|
||||
let _ = buf.set_spans(
|
||||
gauge_area.left(),
|
||||
gauge_area.top(),
|
||||
&inner_label,
|
||||
inner_label.width() as u16,
|
||||
);
|
||||
|
||||
// Short circuit.
|
||||
return;
|
||||
}
|
||||
LabelLimit::Auto(_)
|
||||
if gauge_area.width < (inner_label_width + start_label_width + 1) as u16 =>
|
||||
{
|
||||
let inner_label = self.inner_label.unwrap_or_else(|| Spans::from(""));
|
||||
let _ = buf.set_spans(
|
||||
gauge_area.left(),
|
||||
gauge_area.top(),
|
||||
&inner_label,
|
||||
inner_label.width() as u16,
|
||||
);
|
||||
|
||||
// Short circuit.
|
||||
return;
|
||||
}
|
||||
_ => {
|
||||
let start_label = self.start_label.unwrap_or_else(|| Spans::from(""));
|
||||
buf.set_spans(
|
||||
gauge_area.left(),
|
||||
gauge_area.top(),
|
||||
&start_label,
|
||||
start_label.width() as u16,
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let end_label = self.inner_label.unwrap_or_else(|| Spans::from(""));
|
||||
match self.hide_parts {
|
||||
LabelLimit::Bars => {
|
||||
let _ = buf.set_spans(
|
||||
gauge_area
|
||||
.right()
|
||||
.saturating_sub(end_label.width() as u16 + 1),
|
||||
row,
|
||||
&end_label,
|
||||
end_label.width() as u16,
|
||||
);
|
||||
}
|
||||
LabelLimit::Auto(width_limit)
|
||||
if gauge_area.right().saturating_sub(col) < width_limit =>
|
||||
{
|
||||
let _ = buf.set_spans(
|
||||
gauge_area
|
||||
.right()
|
||||
.saturating_sub(end_label.width() as u16 + 1),
|
||||
row,
|
||||
&end_label,
|
||||
1,
|
||||
);
|
||||
}
|
||||
LabelLimit::Auto(_) | LabelLimit::None => {
|
||||
let (start, _) = buf.set_spans(col, row, &Spans::from("["), gauge_area.width);
|
||||
if start >= gauge_area.right() {
|
||||
return;
|
||||
}
|
||||
|
||||
let (end, _) = buf.set_spans(
|
||||
(gauge_area.x + gauge_area.width).saturating_sub(1),
|
||||
row,
|
||||
&Spans::from("]"),
|
||||
gauge_area.width,
|
||||
);
|
||||
|
||||
let pipe_end =
|
||||
start + (f64::from(end.saturating_sub(start)) * self.ratio).floor() as u16;
|
||||
for col in start..pipe_end {
|
||||
buf.get_mut(col, row).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,
|
||||
});
|
||||
}
|
||||
|
||||
if (end_label.width() as u16) < end.saturating_sub(start) {
|
||||
let gauge_end = gauge_area
|
||||
.right()
|
||||
.saturating_sub(end_label.width() as u16 + 1);
|
||||
buf.set_spans(gauge_end, row, &end_label, end_label.width() as u16);
|
||||
}
|
||||
}
|
||||
LabelLimit::StartLabel => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue