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:
Clement Tsang
2026-05-07 01:47:25 -04:00
committed by GitHub
parent e6700c9899
commit f52ad0acab
7 changed files with 101 additions and 106 deletions
+7 -29
View File
@@ -196,31 +196,19 @@ impl App {
// Reset zoom.
// 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() {
widget_state.time_series_state.reset_zoom(
self.app_config_fields.default_time_value,
self.app_config_fields.autohide_time,
);
widget_state.time_series_state.reset_zoom();
}
for widget_state in self.states.mem_state.widget_states.values_mut() {
widget_state.time_series_state.reset_zoom(
self.app_config_fields.default_time_value,
self.app_config_fields.autohide_time,
);
widget_state.time_series_state.reset_zoom();
}
for widget_state in self.states.net_state.widget_states.values_mut() {
widget_state.time_series_state.reset_zoom(
self.app_config_fields.default_time_value,
self.app_config_fields.autohide_time,
);
widget_state.time_series_state.reset_zoom();
}
for widget_state in self.states.temp_graph_state.widget_states.values_mut() {
widget_state.time_series_state.reset_zoom(
self.app_config_fields.default_time_value,
self.app_config_fields.autohide_time,
);
widget_state.time_series_state.reset_zoom();
}
}
@@ -2027,30 +2015,20 @@ impl App {
}
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() {
ts_state.zoom_out(time_interval, retention_ms, autohide_time);
ts_state.zoom_out();
}
}
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() {
ts_state.zoom_in(time_interval, autohide_time);
ts_state.zoom_in();
}
}
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() {
ts_state.reset_zoom(default_time_value, autohide_time);
ts_state.reset_zoom();
}
}
+10 -8
View File
@@ -379,6 +379,13 @@ pub(crate) fn init_app(args: BottomArgs, config: Config) -> Result<(App, BottomL
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 {
is_case_sensitive,
is_match_whole_word,
@@ -432,7 +439,6 @@ pub(crate) fn init_app(args: BottomArgs, config: Config) -> Result<(App, BottomL
CpuWidgetState::new(
&app_config_fields,
default_cpu_selection,
default_time_value,
autohide_timer,
&styling,
),
@@ -441,13 +447,13 @@ pub(crate) fn init_app(args: BottomArgs, config: Config) -> Result<(App, BottomL
Mem => {
mem_state_map.insert(
widget.widget_id,
MemWidgetState::init(default_time_value, autohide_timer),
MemWidgetState::init(ts_config, autohide_timer),
);
}
Net => {
net_state_map.insert(
widget.widget_id,
NetWidgetState::init(default_time_value, autohide_timer),
NetWidgetState::init(ts_config, autohide_timer),
);
}
Proc => {
@@ -494,11 +500,7 @@ pub(crate) fn init_app(args: BottomArgs, config: Config) -> Result<(App, BottomL
.map(|v| v as f32);
temp_graph_state_map.insert(
widget.widget_id,
TempGraphWidgetState::new(
default_time_value,
autohide_timer,
upper_limit,
),
TempGraphWidgetState::new(ts_config, autohide_timer, upper_limit),
);
}
Battery => {
+63 -52
View File
@@ -7,17 +7,28 @@ use timeless::data::ChunkedData;
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.
pub struct TimeseriesState {
config: TimeseriesConfig,
current_display_time: u64,
autohide_timer: Option<Instant>,
}
impl TimeseriesState {
/// Create a new [`TimeseriesState`] that displays starting from `starting_time`.
pub fn new(starting_time: u64) -> Self {
/// Create a new [`TimeseriesState`] using the given config.
pub fn new(config: TimeseriesConfig) -> Self {
Self {
current_display_time: starting_time,
current_display_time: config.default_time_value,
config,
autohide_timer: None,
}
}
@@ -39,30 +50,33 @@ impl TimeseriesState {
}
/// Zoom in on the x-axis (reducing the time range shown).
pub fn zoom_in(&mut self, time_interval: u64, autohide_time: bool) {
let new_time = self.current_display_time.saturating_sub(time_interval);
pub fn zoom_in(&mut self) {
let new_time = self
.current_display_time
.saturating_sub(self.config.time_interval);
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).
pub fn zoom_out(&mut self, time_interval: u64, retention_ms: u64, autohide_time: bool) {
let new_time = self.current_display_time.saturating_add(time_interval);
pub fn zoom_out(&mut self) {
let new_time = self
.current_display_time
.saturating_add(self.config.time_interval);
self.current_display_time = min(new_time, retention_ms);
self.maybe_start_autohide(autohide_time);
self.current_display_time = min(new_time, self.config.retention_ms);
self.maybe_start_autohide();
}
/// Reset the zoom level to the default.
pub fn reset_zoom(&mut self, default_time_value: u64, autohide_time: bool) {
self.current_display_time = default_time_value;
self.maybe_start_autohide(autohide_time);
pub fn reset_zoom(&mut self) {
self.current_display_time = self.config.default_time_value;
self.maybe_start_autohide();
}
/// Set the autohide timer if needed.
fn maybe_start_autohide(&mut self, autohide_time: bool) {
if autohide_time {
fn maybe_start_autohide(&mut self) {
if self.config.autohide_time {
self.autohide_timer = Some(Instant::now());
}
}
@@ -153,69 +167,66 @@ impl GraphHeightCache {
mod time_series_tests {
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]
fn zoom_in_decreases_display_time() {
let mut state = TimeseriesState {
current_display_time: 60_000,
autohide_timer: None,
};
state.zoom_in(15_000, false);
let mut state = state_at(60_000, TEST_CONFIG);
state.zoom_in();
assert_eq!(state.current_display_time, 45_000);
}
#[test]
fn zoom_in_clamps_at_minimum() {
let mut state = TimeseriesState {
current_display_time: 35_000,
autohide_timer: None,
};
state.zoom_in(15_000, false);
let mut state = state_at(35_000, TEST_CONFIG);
state.zoom_in();
assert_eq!(state.current_display_time, STALE_MIN_MILLISECONDS); // 30_000
}
#[test]
fn zoom_out_increases_display_time() {
let mut state = TimeseriesState {
current_display_time: 60_000,
autohide_timer: None,
};
state.zoom_out(15_000, 300_000, false);
let mut state = state_at(60_000, TEST_CONFIG);
state.zoom_out();
assert_eq!(state.current_display_time, 75_000);
}
#[test]
fn zoom_out_clamps_at_retention() {
let mut state = TimeseriesState {
current_display_time: 290_000,
autohide_timer: None,
};
state.zoom_out(15_000, 300_000, false);
let mut state = state_at(290_000, TEST_CONFIG);
state.zoom_out();
assert_eq!(state.current_display_time, 300_000);
}
#[test]
fn reset_zoom_restores_default() {
let mut state = TimeseriesState {
current_display_time: 120_000,
autohide_timer: None,
};
state.reset_zoom(60_000, false);
let mut state = state_at(120_000, TEST_CONFIG);
state.reset_zoom();
assert_eq!(state.current_display_time, 60_000);
}
#[test]
fn autohide_armed_on_change() {
let mut state = TimeseriesState {
current_display_time: 60_000,
autohide_timer: None,
};
state.zoom_in(15_000, true);
let mut state = state_at(
60_000,
TimeseriesConfig {
autohide_time: true,
..TEST_CONFIG
},
);
state.zoom_in();
assert!(state.autohide_timer.is_some());
}
}
+10 -5
View File
@@ -14,7 +14,7 @@ use crate::{
},
collection::cpu::{CpuData, CpuDataType},
options::config::{cpu::CpuDefault, style::Styles},
widgets::TimeseriesState,
widgets::{TimeseriesConfig, TimeseriesState},
};
pub enum CpuWidgetColumn {
@@ -134,9 +134,15 @@ pub struct CpuWidgetState {
impl CpuWidgetState {
pub(crate) fn new(
config: &AppConfigFields, default_selection: CpuDefault, starting_time: u64,
autohide_timer: Option<Instant>, colours: &Styles,
config: &AppConfigFields, default_selection: CpuDefault, autohide_timer: Option<Instant>,
colours: &Styles,
) -> 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 = [
Column::soft(CpuWidgetColumn::Cpu, Some(0.5)),
Column::soft(
@@ -168,8 +174,7 @@ impl CpuWidgetState {
}
CpuWidgetState {
time_series_state: TimeseriesState::new(starting_time)
.with_autohide_timer(autohide_timer),
time_series_state: TimeseriesState::new(ts_config).with_autohide_timer(autohide_timer),
is_legend_hidden: false,
table,
force_update_data: false,
+3 -4
View File
@@ -1,16 +1,15 @@
use std::time::Instant;
use crate::widgets::TimeseriesState;
use crate::widgets::{TimeseriesConfig, TimeseriesState};
pub struct MemWidgetState {
pub time_series_state: TimeseriesState,
}
impl MemWidgetState {
pub fn init(starting_time: u64, autohide_timer: Option<Instant>) -> Self {
pub fn init(config: TimeseriesConfig, autohide_timer: Option<Instant>) -> Self {
MemWidgetState {
time_series_state: TimeseriesState::new(starting_time)
.with_autohide_timer(autohide_timer),
time_series_state: TimeseriesState::new(config).with_autohide_timer(autohide_timer),
}
}
}
+3 -4
View File
@@ -1,6 +1,6 @@
use std::time::Instant;
use crate::widgets::{GraphHeightCache, TimeseriesState};
use crate::widgets::{GraphHeightCache, TimeseriesConfig, TimeseriesState};
pub struct NetWidgetState {
pub time_series_state: TimeseriesState,
@@ -8,10 +8,9 @@ pub struct 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 {
time_series_state: TimeseriesState::new(starting_time)
.with_autohide_timer(autohide_timer),
time_series_state: TimeseriesState::new(config).with_autohide_timer(autohide_timer),
height_cache: GraphHeightCache::default(),
}
}
+5 -4
View File
@@ -2,7 +2,7 @@
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.
pub struct TempGraphWidgetState {
@@ -12,10 +12,11 @@ pub struct 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 {
time_series_state: TimeseriesState::new(starting_time)
.with_autohide_timer(autohide_timer),
time_series_state: TimeseriesState::new(config).with_autohide_timer(autohide_timer),
height_cache: GraphHeightCache::default(),
max_temp,
}