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}