mirror of
https://github.com/ClementTsang/bottom.git
synced 2026-07-08 13:40:53 +00:00
refactor: more time series graph cleanup (#2054)
Moves all the stuff I was passing around on each zoom function call as just part of the widget state.
This commit is contained in:
+7
-29
@@ -196,31 +196,19 @@ impl App {
|
|||||||
// Reset zoom.
|
// Reset zoom.
|
||||||
// TODO: Make this suck less... should just make it so that calling reset fixes this all (including above too).
|
// TODO: Make this suck less... should just make it so that calling reset fixes this all (including above too).
|
||||||
for widget_state in self.states.cpu_state.widget_states.values_mut() {
|
for widget_state in self.states.cpu_state.widget_states.values_mut() {
|
||||||
widget_state.time_series_state.reset_zoom(
|
widget_state.time_series_state.reset_zoom();
|
||||||
self.app_config_fields.default_time_value,
|
|
||||||
self.app_config_fields.autohide_time,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for widget_state in self.states.mem_state.widget_states.values_mut() {
|
for widget_state in self.states.mem_state.widget_states.values_mut() {
|
||||||
widget_state.time_series_state.reset_zoom(
|
widget_state.time_series_state.reset_zoom();
|
||||||
self.app_config_fields.default_time_value,
|
|
||||||
self.app_config_fields.autohide_time,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for widget_state in self.states.net_state.widget_states.values_mut() {
|
for widget_state in self.states.net_state.widget_states.values_mut() {
|
||||||
widget_state.time_series_state.reset_zoom(
|
widget_state.time_series_state.reset_zoom();
|
||||||
self.app_config_fields.default_time_value,
|
|
||||||
self.app_config_fields.autohide_time,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for widget_state in self.states.temp_graph_state.widget_states.values_mut() {
|
for widget_state in self.states.temp_graph_state.widget_states.values_mut() {
|
||||||
widget_state.time_series_state.reset_zoom(
|
widget_state.time_series_state.reset_zoom();
|
||||||
self.app_config_fields.default_time_value,
|
|
||||||
self.app_config_fields.autohide_time,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2027,30 +2015,20 @@ impl App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn zoom_out(&mut self) {
|
fn zoom_out(&mut self) {
|
||||||
let time_interval = self.app_config_fields.time_interval;
|
|
||||||
let retention_ms = self.app_config_fields.retention_ms;
|
|
||||||
let autohide_time = self.app_config_fields.autohide_time;
|
|
||||||
|
|
||||||
if let Some(ts_state) = self.current_ts_state() {
|
if let Some(ts_state) = self.current_ts_state() {
|
||||||
ts_state.zoom_out(time_interval, retention_ms, autohide_time);
|
ts_state.zoom_out();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn zoom_in(&mut self) {
|
fn zoom_in(&mut self) {
|
||||||
let time_interval = self.app_config_fields.time_interval;
|
|
||||||
let autohide_time = self.app_config_fields.autohide_time;
|
|
||||||
|
|
||||||
if let Some(ts_state) = self.current_ts_state() {
|
if let Some(ts_state) = self.current_ts_state() {
|
||||||
ts_state.zoom_in(time_interval, autohide_time);
|
ts_state.zoom_in();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset_zoom(&mut self) {
|
fn reset_zoom(&mut self) {
|
||||||
let default_time_value = self.app_config_fields.default_time_value;
|
|
||||||
let autohide_time = self.app_config_fields.autohide_time;
|
|
||||||
|
|
||||||
if let Some(ts_state) = self.current_ts_state() {
|
if let Some(ts_state) = self.current_ts_state() {
|
||||||
ts_state.reset_zoom(default_time_value, autohide_time);
|
ts_state.reset_zoom();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
-8
@@ -379,6 +379,13 @@ pub(crate) fn init_app(args: BottomArgs, config: Config) -> Result<(App, BottomL
|
|||||||
temperature_legend_position,
|
temperature_legend_position,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let ts_config = TimeseriesConfig {
|
||||||
|
time_interval: app_config_fields.time_interval,
|
||||||
|
retention_ms: app_config_fields.retention_ms,
|
||||||
|
autohide_time: app_config_fields.autohide_time,
|
||||||
|
default_time_value: app_config_fields.default_time_value,
|
||||||
|
};
|
||||||
|
|
||||||
let table_config = ProcTableConfig {
|
let table_config = ProcTableConfig {
|
||||||
is_case_sensitive,
|
is_case_sensitive,
|
||||||
is_match_whole_word,
|
is_match_whole_word,
|
||||||
@@ -432,7 +439,6 @@ pub(crate) fn init_app(args: BottomArgs, config: Config) -> Result<(App, BottomL
|
|||||||
CpuWidgetState::new(
|
CpuWidgetState::new(
|
||||||
&app_config_fields,
|
&app_config_fields,
|
||||||
default_cpu_selection,
|
default_cpu_selection,
|
||||||
default_time_value,
|
|
||||||
autohide_timer,
|
autohide_timer,
|
||||||
&styling,
|
&styling,
|
||||||
),
|
),
|
||||||
@@ -441,13 +447,13 @@ pub(crate) fn init_app(args: BottomArgs, config: Config) -> Result<(App, BottomL
|
|||||||
Mem => {
|
Mem => {
|
||||||
mem_state_map.insert(
|
mem_state_map.insert(
|
||||||
widget.widget_id,
|
widget.widget_id,
|
||||||
MemWidgetState::init(default_time_value, autohide_timer),
|
MemWidgetState::init(ts_config, autohide_timer),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Net => {
|
Net => {
|
||||||
net_state_map.insert(
|
net_state_map.insert(
|
||||||
widget.widget_id,
|
widget.widget_id,
|
||||||
NetWidgetState::init(default_time_value, autohide_timer),
|
NetWidgetState::init(ts_config, autohide_timer),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Proc => {
|
Proc => {
|
||||||
@@ -494,11 +500,7 @@ pub(crate) fn init_app(args: BottomArgs, config: Config) -> Result<(App, BottomL
|
|||||||
.map(|v| v as f32);
|
.map(|v| v as f32);
|
||||||
temp_graph_state_map.insert(
|
temp_graph_state_map.insert(
|
||||||
widget.widget_id,
|
widget.widget_id,
|
||||||
TempGraphWidgetState::new(
|
TempGraphWidgetState::new(ts_config, autohide_timer, upper_limit),
|
||||||
default_time_value,
|
|
||||||
autohide_timer,
|
|
||||||
upper_limit,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Battery => {
|
Battery => {
|
||||||
|
|||||||
@@ -7,17 +7,28 @@ use timeless::data::ChunkedData;
|
|||||||
|
|
||||||
const STALE_MIN_MILLISECONDS: u64 = Duration::from_secs(30).as_millis() as u64;
|
const STALE_MIN_MILLISECONDS: u64 = Duration::from_secs(30).as_millis() as u64;
|
||||||
|
|
||||||
|
/// Configuration values for a [`TimeseriesState`], sourced from [`crate::app::AppConfigFields`].
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct TimeseriesConfig {
|
||||||
|
pub time_interval: u64,
|
||||||
|
pub retention_ms: u64,
|
||||||
|
pub autohide_time: bool,
|
||||||
|
pub default_time_value: u64,
|
||||||
|
}
|
||||||
|
|
||||||
/// A time_series graph widget displays data over a period of time.
|
/// A time_series graph widget displays data over a period of time.
|
||||||
pub struct TimeseriesState {
|
pub struct TimeseriesState {
|
||||||
|
config: TimeseriesConfig,
|
||||||
current_display_time: u64,
|
current_display_time: u64,
|
||||||
autohide_timer: Option<Instant>,
|
autohide_timer: Option<Instant>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TimeseriesState {
|
impl TimeseriesState {
|
||||||
/// Create a new [`TimeseriesState`] that displays starting from `starting_time`.
|
/// Create a new [`TimeseriesState`] using the given config.
|
||||||
pub fn new(starting_time: u64) -> Self {
|
pub fn new(config: TimeseriesConfig) -> Self {
|
||||||
Self {
|
Self {
|
||||||
current_display_time: starting_time,
|
current_display_time: config.default_time_value,
|
||||||
|
config,
|
||||||
autohide_timer: None,
|
autohide_timer: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -39,30 +50,33 @@ impl TimeseriesState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Zoom in on the x-axis (reducing the time range shown).
|
/// Zoom in on the x-axis (reducing the time range shown).
|
||||||
pub fn zoom_in(&mut self, time_interval: u64, autohide_time: bool) {
|
pub fn zoom_in(&mut self) {
|
||||||
let new_time = self.current_display_time.saturating_sub(time_interval);
|
let new_time = self
|
||||||
|
.current_display_time
|
||||||
|
.saturating_sub(self.config.time_interval);
|
||||||
|
|
||||||
self.current_display_time = max(new_time, STALE_MIN_MILLISECONDS);
|
self.current_display_time = max(new_time, STALE_MIN_MILLISECONDS);
|
||||||
self.maybe_start_autohide(autohide_time);
|
self.maybe_start_autohide();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Zoom out on the x-axis (increasing the time range shown).
|
/// Zoom out on the x-axis (increasing the time range shown).
|
||||||
pub fn zoom_out(&mut self, time_interval: u64, retention_ms: u64, autohide_time: bool) {
|
pub fn zoom_out(&mut self) {
|
||||||
let new_time = self.current_display_time.saturating_add(time_interval);
|
let new_time = self
|
||||||
|
.current_display_time
|
||||||
|
.saturating_add(self.config.time_interval);
|
||||||
|
|
||||||
self.current_display_time = min(new_time, retention_ms);
|
self.current_display_time = min(new_time, self.config.retention_ms);
|
||||||
self.maybe_start_autohide(autohide_time);
|
self.maybe_start_autohide();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reset the zoom level to the default.
|
/// Reset the zoom level to the default.
|
||||||
pub fn reset_zoom(&mut self, default_time_value: u64, autohide_time: bool) {
|
pub fn reset_zoom(&mut self) {
|
||||||
self.current_display_time = default_time_value;
|
self.current_display_time = self.config.default_time_value;
|
||||||
self.maybe_start_autohide(autohide_time);
|
self.maybe_start_autohide();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the autohide timer if needed.
|
fn maybe_start_autohide(&mut self) {
|
||||||
fn maybe_start_autohide(&mut self, autohide_time: bool) {
|
if self.config.autohide_time {
|
||||||
if autohide_time {
|
|
||||||
self.autohide_timer = Some(Instant::now());
|
self.autohide_timer = Some(Instant::now());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,69 +167,66 @@ impl GraphHeightCache {
|
|||||||
mod time_series_tests {
|
mod time_series_tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
const TEST_CONFIG: TimeseriesConfig = TimeseriesConfig {
|
||||||
|
time_interval: 15_000,
|
||||||
|
retention_ms: 300_000,
|
||||||
|
autohide_time: false,
|
||||||
|
default_time_value: 60_000,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn state_at(display_time: u64, cfg: TimeseriesConfig) -> TimeseriesState {
|
||||||
|
TimeseriesState {
|
||||||
|
config: cfg,
|
||||||
|
current_display_time: display_time,
|
||||||
|
autohide_timer: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn zoom_in_decreases_display_time() {
|
fn zoom_in_decreases_display_time() {
|
||||||
let mut state = TimeseriesState {
|
let mut state = state_at(60_000, TEST_CONFIG);
|
||||||
current_display_time: 60_000,
|
state.zoom_in();
|
||||||
autohide_timer: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
state.zoom_in(15_000, false);
|
|
||||||
assert_eq!(state.current_display_time, 45_000);
|
assert_eq!(state.current_display_time, 45_000);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn zoom_in_clamps_at_minimum() {
|
fn zoom_in_clamps_at_minimum() {
|
||||||
let mut state = TimeseriesState {
|
let mut state = state_at(35_000, TEST_CONFIG);
|
||||||
current_display_time: 35_000,
|
state.zoom_in();
|
||||||
autohide_timer: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
state.zoom_in(15_000, false);
|
|
||||||
assert_eq!(state.current_display_time, STALE_MIN_MILLISECONDS); // 30_000
|
assert_eq!(state.current_display_time, STALE_MIN_MILLISECONDS); // 30_000
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn zoom_out_increases_display_time() {
|
fn zoom_out_increases_display_time() {
|
||||||
let mut state = TimeseriesState {
|
let mut state = state_at(60_000, TEST_CONFIG);
|
||||||
current_display_time: 60_000,
|
state.zoom_out();
|
||||||
autohide_timer: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
state.zoom_out(15_000, 300_000, false);
|
|
||||||
assert_eq!(state.current_display_time, 75_000);
|
assert_eq!(state.current_display_time, 75_000);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn zoom_out_clamps_at_retention() {
|
fn zoom_out_clamps_at_retention() {
|
||||||
let mut state = TimeseriesState {
|
let mut state = state_at(290_000, TEST_CONFIG);
|
||||||
current_display_time: 290_000,
|
state.zoom_out();
|
||||||
autohide_timer: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
state.zoom_out(15_000, 300_000, false);
|
|
||||||
assert_eq!(state.current_display_time, 300_000);
|
assert_eq!(state.current_display_time, 300_000);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn reset_zoom_restores_default() {
|
fn reset_zoom_restores_default() {
|
||||||
let mut state = TimeseriesState {
|
let mut state = state_at(120_000, TEST_CONFIG);
|
||||||
current_display_time: 120_000,
|
state.reset_zoom();
|
||||||
autohide_timer: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
state.reset_zoom(60_000, false);
|
|
||||||
assert_eq!(state.current_display_time, 60_000);
|
assert_eq!(state.current_display_time, 60_000);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn autohide_armed_on_change() {
|
fn autohide_armed_on_change() {
|
||||||
let mut state = TimeseriesState {
|
let mut state = state_at(
|
||||||
current_display_time: 60_000,
|
60_000,
|
||||||
autohide_timer: None,
|
TimeseriesConfig {
|
||||||
};
|
autohide_time: true,
|
||||||
|
..TEST_CONFIG
|
||||||
state.zoom_in(15_000, true);
|
},
|
||||||
|
);
|
||||||
|
state.zoom_in();
|
||||||
assert!(state.autohide_timer.is_some());
|
assert!(state.autohide_timer.is_some());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
collection::cpu::{CpuData, CpuDataType},
|
collection::cpu::{CpuData, CpuDataType},
|
||||||
options::config::{cpu::CpuDefault, style::Styles},
|
options::config::{cpu::CpuDefault, style::Styles},
|
||||||
widgets::TimeseriesState,
|
widgets::{TimeseriesConfig, TimeseriesState},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub enum CpuWidgetColumn {
|
pub enum CpuWidgetColumn {
|
||||||
@@ -134,9 +134,15 @@ pub struct CpuWidgetState {
|
|||||||
|
|
||||||
impl CpuWidgetState {
|
impl CpuWidgetState {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
config: &AppConfigFields, default_selection: CpuDefault, starting_time: u64,
|
config: &AppConfigFields, default_selection: CpuDefault, autohide_timer: Option<Instant>,
|
||||||
autohide_timer: Option<Instant>, colours: &Styles,
|
colours: &Styles,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
let ts_config = TimeseriesConfig {
|
||||||
|
time_interval: config.time_interval,
|
||||||
|
retention_ms: config.retention_ms,
|
||||||
|
autohide_time: config.autohide_time,
|
||||||
|
default_time_value: config.default_time_value,
|
||||||
|
};
|
||||||
let columns = [
|
let columns = [
|
||||||
Column::soft(CpuWidgetColumn::Cpu, Some(0.5)),
|
Column::soft(CpuWidgetColumn::Cpu, Some(0.5)),
|
||||||
Column::soft(
|
Column::soft(
|
||||||
@@ -168,8 +174,7 @@ impl CpuWidgetState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CpuWidgetState {
|
CpuWidgetState {
|
||||||
time_series_state: TimeseriesState::new(starting_time)
|
time_series_state: TimeseriesState::new(ts_config).with_autohide_timer(autohide_timer),
|
||||||
.with_autohide_timer(autohide_timer),
|
|
||||||
is_legend_hidden: false,
|
is_legend_hidden: false,
|
||||||
table,
|
table,
|
||||||
force_update_data: false,
|
force_update_data: false,
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
use crate::widgets::TimeseriesState;
|
use crate::widgets::{TimeseriesConfig, TimeseriesState};
|
||||||
|
|
||||||
pub struct MemWidgetState {
|
pub struct MemWidgetState {
|
||||||
pub time_series_state: TimeseriesState,
|
pub time_series_state: TimeseriesState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MemWidgetState {
|
impl MemWidgetState {
|
||||||
pub fn init(starting_time: u64, autohide_timer: Option<Instant>) -> Self {
|
pub fn init(config: TimeseriesConfig, autohide_timer: Option<Instant>) -> Self {
|
||||||
MemWidgetState {
|
MemWidgetState {
|
||||||
time_series_state: TimeseriesState::new(starting_time)
|
time_series_state: TimeseriesState::new(config).with_autohide_timer(autohide_timer),
|
||||||
.with_autohide_timer(autohide_timer),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
use crate::widgets::{GraphHeightCache, TimeseriesState};
|
use crate::widgets::{GraphHeightCache, TimeseriesConfig, TimeseriesState};
|
||||||
|
|
||||||
pub struct NetWidgetState {
|
pub struct NetWidgetState {
|
||||||
pub time_series_state: TimeseriesState,
|
pub time_series_state: TimeseriesState,
|
||||||
@@ -8,10 +8,9 @@ pub struct NetWidgetState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl NetWidgetState {
|
impl NetWidgetState {
|
||||||
pub fn init(starting_time: u64, autohide_timer: Option<Instant>) -> Self {
|
pub fn init(config: TimeseriesConfig, autohide_timer: Option<Instant>) -> Self {
|
||||||
NetWidgetState {
|
NetWidgetState {
|
||||||
time_series_state: TimeseriesState::new(starting_time)
|
time_series_state: TimeseriesState::new(config).with_autohide_timer(autohide_timer),
|
||||||
.with_autohide_timer(autohide_timer),
|
|
||||||
height_cache: GraphHeightCache::default(),
|
height_cache: GraphHeightCache::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
use crate::widgets::{GraphHeightCache, TimeseriesState};
|
use crate::widgets::{GraphHeightCache, TimeseriesConfig, TimeseriesState};
|
||||||
|
|
||||||
/// A time_series graph widget displaying temperature usage over time.
|
/// A time_series graph widget displaying temperature usage over time.
|
||||||
pub struct TempGraphWidgetState {
|
pub struct TempGraphWidgetState {
|
||||||
@@ -12,10 +12,11 @@ pub struct TempGraphWidgetState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TempGraphWidgetState {
|
impl TempGraphWidgetState {
|
||||||
pub fn new(starting_time: u64, autohide_timer: Option<Instant>, max_temp: Option<f32>) -> Self {
|
pub fn new(
|
||||||
|
config: TimeseriesConfig, autohide_timer: Option<Instant>, max_temp: Option<f32>,
|
||||||
|
) -> Self {
|
||||||
TempGraphWidgetState {
|
TempGraphWidgetState {
|
||||||
time_series_state: TimeseriesState::new(starting_time)
|
time_series_state: TimeseriesState::new(config).with_autohide_timer(autohide_timer),
|
||||||
.with_autohide_timer(autohide_timer),
|
|
||||||
height_cache: GraphHeightCache::default(),
|
height_cache: GraphHeightCache::default(),
|
||||||
max_temp,
|
max_temp,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user