leetcode_tui_shared/
layout.rs

1// ┌─────────────────────────────────────────────────────────────────────────┐
2// │                                  Leetui                                 │
3// │  ┌─Topics─────┐ ┌─Questions──────────────────────────────────────────┐  │
4// │  │            │ │                                                    │  │
5// │  │            │ │                                                    │  │
6// │  │            │ │                                                    │  │
7// │  │          ┌─┘Popup────────────────────────────────────┐            │  │
8// │  │          │                                           │            │  │
9// │  │          │                                           │            │  │
10// │  │          │                                           │            │  │
11// │  │          │                                           │            │  │
12// │  │          │                                           │            │  │
13// │  │          │                                           │            │  │
14// │  │          │                                           │            │  │
15// │  │          │                                           │            │  │
16// │  │          │                                           │            │  │
17// │  │          │                                           │            │  │
18// │  │          │                                           │            │  │
19// │  │          │                                           │            │  │
20// │  │          │                                           │            │  │
21// │  │          │                                           │            │  │
22// │  │          └─┬─┬───────────────────────────────────────┘            │  │
23// │  │            │ │                                                    │  │
24// │  │            │ │                                                    │  │
25// │  │            │ │                                                    │  │
26// │  │            │ │                                                    │  │
27// │  └────────────┘ └────────────────────────────────────────────────────┘  │
28// │  /search                                                      [?] Help  │
29// └─────────────────────────────────────────────────────────────────────────┘
30
31// ┌─────────────────────────────────────────────────────────────────────────┐
32// │                                  Leetui                                 │
33// │  ┌─Topics─────┐ ┌─Stats──────────────────────────────────────────────┐  │
34// │  │            │ │                                                    │  │
35// │  │            │ │                                                    │  │
36// │  │            │ │                                                    │  │
37// │  │            │ │                                                    │  │
38// │  │            │ │                                                    │  │
39// │  │            │ │                                                    │  │
40// │  │            │ │                                                    │  │
41// │  │            │ │                                                    │  │
42// │  │            │ │                                                    │  │
43// │  │            │ │                                                    │  │
44// │  │            │ │                                                    │  │
45// │  │            │ │                                                    │  │
46// │  │            │ │                                                    │  │
47// │  │            │ │                                                    │  │
48// │  │            │ │                                                    │  │
49// │  │            │ │                                                    │  │
50// │  │            │ │                                                    │  │
51// │  │            │ │                                                    │  │
52// │  │            │ │                                                    │  │
53// │  │            │ │                                                    │  │
54// │  │            │ │                                                    │  │
55// │  │            │ │                                                    │  │
56// │  │            │ │                                                    │  │
57// │  └────────────┘ └────────────────────────────────────────────────────┘  │
58// │  /search                                                      [?] Help  │
59// └─────────────────────────────────────────────────────────────────────────┘
60
61use ratatui::{
62    prelude::*,
63    widgets::{Block, Borders, Widget},
64};
65
66#[derive(Debug, Clone)]
67pub struct BlockAreas {
68    pub inner: Rect,
69    pub outer: Rect,
70}
71
72impl From<Rect> for BlockAreas {
73    fn from(value: Rect) -> Self {
74        Self {
75            outer: value,
76            inner: value.blockify(),
77        }
78    }
79}
80
81#[derive(Debug)]
82pub struct Window {
83    pub root: Root,
84}
85
86#[derive(Debug)]
87pub struct StatusBar {
88    pub search_area: Rect,
89    pub message_area: Rect,
90}
91
92impl From<Rect> for StatusBar {
93    fn from(value: Rect) -> Self {
94        let left_and_right_div = Layout::new(
95            Direction::Horizontal,
96            [Constraint::Percentage(50), Constraint::Percentage(50)],
97        )
98        .split(value);
99        Self {
100            search_area: left_and_right_div[0],
101            message_area: left_and_right_div[1],
102        }
103    }
104}
105
106#[derive(Debug)]
107pub struct Root {
108    pub top_bar: Rect,
109    pub center_layout: CenterLayout,
110    pub status_bar: StatusBar,
111    pub popup: BlockAreas,
112    pub q_stats: BlockAreas,
113}
114
115#[derive(Debug)]
116pub struct CenterLayout {
117    pub question: BlockAreas,
118    pub topic: BlockAreas,
119}
120
121impl CenterLayout {
122    fn new(chunks: Rect) -> Self {
123        let center_chunks = Layout::new(
124            Direction::Horizontal,
125            [Constraint::Percentage(20), Constraint::Percentage(80)].as_ref(),
126        )
127        .split(chunks);
128
129        let topic_area = center_chunks[0];
130        let question_area = center_chunks[1];
131        Self {
132            question: question_area.into(),
133            topic: topic_area.into(),
134        }
135    }
136}
137
138impl Root {
139    fn new(ar: Rect) -> Self {
140        let chunks = Layout::new(
141            Direction::Vertical,
142            [
143                Constraint::Length(1),
144                Constraint::Min(0),
145                Constraint::Length(1),
146            ]
147            .as_ref(),
148        )
149        .split(ar);
150
151        let mut r = Self {
152            top_bar: chunks[0],
153            center_layout: CenterLayout::new(chunks[1]),
154            status_bar: chunks[2].into(),
155            popup: centered_rect(60, 60, ar).into(),
156            q_stats: centered_rect(60, 60, ar).into(),
157        };
158        r.q_stats = r.center_layout.question.clone();
159        r
160    }
161}
162
163impl Default for Window {
164    fn default() -> Self {
165        let term_size = super::tui::Term::size();
166        let window_rect = Rect::new(0, 0, term_size.columns, term_size.rows);
167        Self {
168            root: Root::new(window_rect),
169        }
170    }
171}
172
173pub trait GetWindowStats {
174    fn get_window(&self) -> Window {
175        Window::default()
176    }
177}
178
179impl<T> GetWindowStats for T where T: Widget {}
180
181trait Blockify {
182    fn blockify(self) -> Rect;
183}
184
185impl Blockify for Rect {
186    fn blockify(self) -> Rect {
187        Block::default().borders(Borders::ALL).inner(self)
188    }
189}
190
191fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect {
192    let popup_layout = Layout::default()
193        .direction(Direction::Vertical)
194        .constraints(
195            [
196                Constraint::Percentage((100 - percent_y) / 2),
197                Constraint::Percentage(percent_y),
198                Constraint::Percentage((100 - percent_y) / 2),
199            ]
200            .as_ref(),
201        )
202        .split(r);
203
204    Layout::default()
205        .direction(Direction::Horizontal)
206        .constraints(
207            [
208                Constraint::Percentage((100 - percent_x) / 2),
209                Constraint::Percentage(percent_x),
210                Constraint::Percentage((100 - percent_x) / 2),
211            ]
212            .as_ref(),
213        )
214        .split(popup_layout[1])[1]
215}