use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use ratatui::buffer::{Buffer, Cell};
use ratatui::layout::Rect;
use ratatui::widgets::StatefulWidget;
pub use self::add_stock::{AddStockState, AddStockWidget};
pub use self::chart_configuration::{ChartConfigurationWidget, KagiOptions};
pub use self::help::{HelpWidget, HELP_HEIGHT, HELP_WIDTH};
pub use self::options::{OptionsState, OptionsWidget};
pub use self::stock::{StockState, StockWidget};
pub use self::stock_summary::StockSummaryWidget;
mod add_stock;
pub mod block;
mod chart;
pub mod chart_configuration;
mod help;
pub mod options;
mod stock;
mod stock_summary;
pub trait CachableWidget<T: Hash>: StatefulWidget<State = T> + Sized {
fn cache_state_mut(state: &mut <Self as StatefulWidget>::State) -> &mut CacheState;
fn render(self, area: Rect, buf: &mut Buffer, state: &mut <Self as StatefulWidget>::State);
fn render_cached(
self,
area: Rect,
buf: &mut Buffer,
state: &mut <Self as StatefulWidget>::State,
) {
let mut hasher = DefaultHasher::default();
state.hash(&mut hasher);
let hash = hasher.finish();
let CacheState {
prev_area,
prev_content,
prev_hash,
} = <Self as CachableWidget<T>>::cache_state_mut(state).clone();
if hash == prev_hash && prev_area == area {
for (idx, cell) in buf.content.iter_mut().enumerate() {
let x = idx as u16 % buf.area.width;
let y = idx as u16 / buf.area.width;
if x >= area.x && x < area.x + area.width && y >= area.y && y < area.y + area.height
{
if let Some(cached_cell) = prev_content.get(idx) {
*cell = cached_cell.clone();
}
}
}
}
else {
<Self as CachableWidget<T>>::render(self, area, buf, state);
let cached_state = <Self as CachableWidget<T>>::cache_state_mut(state);
cached_state.prev_hash = hash;
cached_state.prev_area = area;
cached_state.prev_content = buf.content.clone();
}
}
}
#[derive(Debug, Clone, Default)]
pub struct CacheState {
prev_area: Rect,
prev_hash: u64,
prev_content: Vec<Cell>,
}