mermaid_cli/tui/state/
ui.rs1use ratatui::layout::{Constraint, Direction, Flex, Layout, Rect};
6use ratatui::text::Line;
7use rustc_hash::FxHashMap;
8
9use crate::tui::theme::Theme;
10use crate::tui::widgets::{ChatState, InputState};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16struct LayoutKey {
17 width: u16,
18 height: u16,
19 input_height: u16,
20 status_line_height: u16,
21 attachment_height: u16,
22 bottom_height: u16,
23}
24
25pub struct LayoutCache {
27 cached: Option<(LayoutKey, Vec<Rect>)>,
28}
29
30impl LayoutCache {
31 fn new() -> Self {
32 Self { cached: None }
33 }
34
35 pub fn get_main_layout(
36 &mut self,
37 area: Rect,
38 input_height: u16,
39 status_line_height: u16,
40 attachment_height: u16,
41 bottom_height: u16,
42 ) -> Vec<Rect> {
43 let key = LayoutKey {
44 width: area.width,
45 height: area.height,
46 input_height,
47 status_line_height,
48 attachment_height,
49 bottom_height,
50 };
51 if let Some((cached_key, ref rects)) = self.cached
52 && cached_key == key
53 {
54 return rects.clone();
55 }
56
57 let layout = Layout::default()
58 .direction(Direction::Vertical)
59 .margin(0)
60 .spacing(0)
61 .flex(Flex::Start)
62 .constraints([
63 Constraint::Min(10),
64 Constraint::Length(status_line_height),
65 Constraint::Length(attachment_height),
66 Constraint::Length(input_height),
67 Constraint::Length(bottom_height),
68 ])
69 .split(area);
70
71 let layout_vec = layout.to_vec();
72 self.cached = Some((key, layout_vec.clone()));
73 layout_vec
74 }
75}
76
77pub struct UIState {
79 pub chat_state: ChatState,
81 pub input_state: InputState,
83 pub theme: Theme,
85 pub selected_message: Option<usize>,
87 pub attachment_focused: bool,
89 pub selected_attachment: usize,
91 pub attachment_area_y: Option<u16>,
93 pub palette_selected_index: usize,
98 pub layout_cache: LayoutCache,
100 pub markdown_cache: FxHashMap<u64, Vec<Line<'static>>>,
102}
103
104impl UIState {
105 pub fn new() -> Self {
107 Self {
108 chat_state: ChatState::default(),
109 input_state: InputState::default(),
110 theme: Theme::dark(),
111 selected_message: None,
112 attachment_focused: false,
113 selected_attachment: 0,
114 attachment_area_y: None,
115 palette_selected_index: 0,
116 layout_cache: LayoutCache::new(),
117 markdown_cache: FxHashMap::default(),
118 }
119 }
120}
121
122impl Default for UIState {
123 fn default() -> Self {
124 Self::new()
125 }
126}