use ratatui::layout::{Constraint, Direction, Flex, Layout, Rect};
use ratatui::text::Line;
use rustc_hash::FxHashMap;
use crate::tui::theme::Theme;
use crate::tui::widgets::{ChatState, InputState};
pub struct LayoutCache {
cached: Option<(u16, u16, u16, u16, u16, Vec<Rect>)>,
}
impl LayoutCache {
fn new() -> Self {
Self { cached: None }
}
pub fn get_main_layout(
&mut self,
area: Rect,
input_height: u16,
status_line_height: u16,
attachment_height: u16,
) -> Vec<Rect> {
if let Some((w, h, ih, sh, ah, ref rects)) = self.cached
&& w == area.width
&& h == area.height
&& ih == input_height
&& sh == status_line_height
&& ah == attachment_height
{
return rects.clone();
}
let layout = Layout::default()
.direction(Direction::Vertical)
.margin(0)
.spacing(0)
.flex(Flex::Start)
.constraints([
Constraint::Min(10),
Constraint::Length(status_line_height),
Constraint::Length(attachment_height),
Constraint::Length(input_height),
Constraint::Length(2),
])
.split(area);
let layout_vec = layout.to_vec();
self.cached = Some((
area.width,
area.height,
input_height,
status_line_height,
attachment_height,
layout_vec.clone(),
));
layout_vec
}
}
pub struct UIState {
pub chat_state: ChatState,
pub input_state: InputState,
pub theme: Theme,
pub selected_message: Option<usize>,
pub attachment_focused: bool,
pub selected_attachment: usize,
pub attachment_area_y: Option<u16>,
pub layout_cache: LayoutCache,
pub markdown_cache: FxHashMap<u64, Vec<Line<'static>>>,
}
impl UIState {
pub fn new() -> Self {
Self {
chat_state: ChatState::default(),
input_state: InputState::default(),
theme: Theme::dark(),
selected_message: None,
attachment_focused: false,
selected_attachment: 0,
attachment_area_y: None,
layout_cache: LayoutCache::new(),
markdown_cache: FxHashMap::default(),
}
}
}
impl Default for UIState {
fn default() -> Self {
Self::new()
}
}