stynx_code_tui/layout/
main_layout.rs1use ratatui::layout::{Constraint, Layout, Rect};
2
3pub struct LayoutResult {
4 pub tool_history: Option<Rect>,
6 pub tool_info: Option<Rect>,
8 pub messages: Rect,
9 pub thinking: Option<Rect>,
10 pub delegate: Option<Rect>,
11 pub summary: Option<Rect>,
12 pub input: Rect,
13 pub footer: Option<Rect>,
16}
17
18pub struct MainLayout;
19
20impl MainLayout {
21 pub const TOOL_HISTORY_WIDTH: u16 = 44;
22 pub const MIN_MAIN_WIDTH: u16 = 60;
23 const INFO_HEIGHT: u16 = 9;
25
26 pub fn split(
27 area: Rect,
28 input_lines: usize,
29 thinking_lines: usize,
30 delegate_lines: usize,
31 has_summary: bool,
32 ) -> LayoutResult {
33 let (tool_col, main) = if area.width > Self::TOOL_HISTORY_WIDTH + Self::MIN_MAIN_WIDTH {
34 let chunks = Layout::horizontal([
35 Constraint::Length(Self::TOOL_HISTORY_WIDTH),
36 Constraint::Min(1),
37 ])
38 .split(area);
39 (Some(chunks[0]), chunks[1])
40 } else {
41 (None, area)
42 };
43
44 let (tool_history, tool_info) = match tool_col {
46 Some(col) => {
47 let info_h = Self::INFO_HEIGHT.min(col.height.saturating_sub(3));
48 if info_h >= 4 {
49 let parts = Layout::vertical([
50 Constraint::Min(1),
51 Constraint::Length(info_h),
52 ])
53 .split(col);
54 (Some(parts[0]), Some(parts[1]))
55 } else {
56 (Some(col), None)
57 }
58 }
59 None => (None, None),
60 };
61
62 let content = input_lines.clamp(1, 8) as u16;
63 let input_h = (content + 2).min(main.height.saturating_sub(4));
64 let thinking_h: u16 = if thinking_lines == 0 {
65 0
66 } else {
67 (1 + thinking_lines.min(12)) as u16
68 };
69 let delegate_h: u16 = delegate_lines.min(4) as u16;
70 let footer_h: u16 = if tool_info.is_some() { 0 } else { 1 };
72
73 let mut constraints: Vec<Constraint> = vec![Constraint::Min(1)];
74 if thinking_h > 0 { constraints.push(Constraint::Length(thinking_h)); }
75 if delegate_h > 0 { constraints.push(Constraint::Length(delegate_h)); }
76 if has_summary { constraints.push(Constraint::Length(1)); }
77 constraints.push(Constraint::Length(input_h));
78 if footer_h > 0 { constraints.push(Constraint::Length(footer_h)); }
79
80 let rows = Layout::vertical(constraints).split(main);
81 let mut idx = 0;
82 let messages = rows[idx]; idx += 1;
83 let thinking = if thinking_h > 0 { let r = Some(rows[idx]); idx += 1; r } else { None };
84 let delegate = if delegate_h > 0 { let r = Some(rows[idx]); idx += 1; r } else { None };
85 let summary = if has_summary { let r = Some(rows[idx]); idx += 1; r } else { None };
86 let input = rows[idx]; idx += 1;
87 let footer = if footer_h > 0 { Some(rows[idx]) } else { None };
88
89 LayoutResult { tool_history, tool_info, messages, thinking, delegate, summary, input, footer }
90 }
91}