1use crate::{
2 framework::info::{FrameworkInfo, PdPortInfo},
3 tui::{component::Component, theme::Theme},
4};
5use ratatui::{
6 layout::{Constraint, Flex, Layout, Rect},
7 style::Style,
8 widgets::{Block, BorderType, Borders, Paragraph},
9 Frame,
10};
11
12pub struct PdPortsPanelComponent;
13
14impl Default for PdPortsPanelComponent {
15 fn default() -> Self {
16 Self::new()
17 }
18}
19
20impl PdPortsPanelComponent {
21 pub fn new() -> Self {
22 PdPortsPanelComponent
23 }
24
25 fn render_port_block(
26 &self,
27 frame: &mut Frame,
28 area: Rect,
29 name: &str,
30 theme: &Theme,
31 info: &Option<PdPortInfo>,
32 ) {
33 let block = Block::default()
34 .title(format!(" {} ", name))
35 .borders(Borders::ALL)
36 .border_type(BorderType::Plain);
37
38 if let Some(info) = info {
39 let [key_area, value_area] =
40 Layout::horizontal([Constraint::Fill(1), Constraint::Fill(1)])
41 .margin(1)
42 .spacing(1)
43 .areas(block.inner(area));
44
45 let keys_block = Block::default().borders(Borders::NONE);
46 let values_block = Block::default().borders(Borders::NONE);
47
48 let [role_key_area, dualrole_key_area, charging_type_key_area, voltage_now_key_area, voltage_max_key_area, current_limit_key_area, current_max_key_area, max_power_key_area] =
49 Layout::vertical([
50 Constraint::Length(1),
51 Constraint::Length(1),
52 Constraint::Length(1),
53 Constraint::Length(1),
54 Constraint::Length(1),
55 Constraint::Length(1),
56 Constraint::Length(1),
57 Constraint::Length(1),
58 ])
59 .flex(Flex::Legacy)
60 .areas(keys_block.inner(key_area));
61 let [role_value_area, dualrole_value_area, charging_type_value_area, voltage_now_value_area, voltage_max_value_area, current_limit_value_area, current_max_value_area, max_power_value_area] =
62 Layout::vertical([
63 Constraint::Length(1),
64 Constraint::Length(1),
65 Constraint::Length(1),
66 Constraint::Length(1),
67 Constraint::Length(1),
68 Constraint::Length(1),
69 Constraint::Length(1),
70 Constraint::Length(1),
71 ])
72 .flex(Flex::Legacy)
73 .areas(values_block.inner(value_area));
74
75 self.render_role(frame, role_key_area, role_value_area, theme, info);
76 self.render_dualrole(frame, dualrole_key_area, dualrole_value_area, theme, info);
77 self.render_charging_type(
78 frame,
79 charging_type_key_area,
80 charging_type_value_area,
81 theme,
82 info,
83 );
84 self.render_voltage_now(
85 frame,
86 voltage_now_key_area,
87 voltage_now_value_area,
88 theme,
89 info,
90 );
91 self.render_voltage_max(
92 frame,
93 voltage_max_key_area,
94 voltage_max_value_area,
95 theme,
96 info,
97 );
98 self.render_current_limit(
99 frame,
100 current_limit_key_area,
101 current_limit_value_area,
102 theme,
103 info,
104 );
105 self.render_current_max(
106 frame,
107 current_max_key_area,
108 current_max_value_area,
109 theme,
110 info,
111 );
112 self.render_max_power(frame, max_power_key_area, max_power_value_area, theme, info);
113 }
114
115 frame.render_widget(block, area);
116 }
117
118 fn render_role(
119 &self,
120 frame: &mut Frame,
121 key_area: Rect,
122 value_area: Rect,
123 theme: &Theme,
124 info: &PdPortInfo,
125 ) {
126 frame.render_widget(Paragraph::new("Role"), key_area);
127 frame.render_widget(
128 Paragraph::new(info.role.as_str()).style(Style::default().fg(theme.informative_text)),
129 value_area,
130 );
131 }
132
133 fn render_dualrole(
134 &self,
135 frame: &mut Frame,
136 key_area: Rect,
137 value_area: Rect,
138 theme: &Theme,
139 info: &PdPortInfo,
140 ) {
141 frame.render_widget(Paragraph::new("Dual role"), key_area);
142 frame.render_widget(
143 Paragraph::new(info.dualrole.as_str())
144 .style(Style::default().fg(theme.informative_text)),
145 value_area,
146 );
147 }
148
149 fn render_charging_type(
150 &self,
151 frame: &mut Frame,
152 key_area: Rect,
153 value_area: Rect,
154 theme: &Theme,
155 info: &PdPortInfo,
156 ) {
157 frame.render_widget(Paragraph::new("Charging type"), key_area);
158 frame.render_widget(
159 Paragraph::new(info.charging_type.as_str())
160 .style(Style::default().fg(theme.informative_text)),
161 value_area,
162 );
163 }
164
165 fn render_voltage_now(
166 &self,
167 frame: &mut Frame,
168 key_area: Rect,
169 value_area: Rect,
170 theme: &Theme,
171 info: &PdPortInfo,
172 ) {
173 frame.render_widget(Paragraph::new("Voltage now"), key_area);
174 frame.render_widget(
175 Paragraph::new(format!("{:.1} V", info.voltage_now))
176 .style(Style::default().fg(theme.informative_text)),
177 value_area,
178 );
179 }
180
181 fn render_voltage_max(
182 &self,
183 frame: &mut Frame,
184 key_area: Rect,
185 value_area: Rect,
186 theme: &Theme,
187 info: &PdPortInfo,
188 ) {
189 frame.render_widget(Paragraph::new("Voltage max"), key_area);
190 frame.render_widget(
191 Paragraph::new(format!("{:.1} V", info.voltage_max))
192 .style(Style::default().fg(theme.informative_text)),
193 value_area,
194 );
195 }
196
197 fn render_current_limit(
198 &self,
199 frame: &mut Frame,
200 key_area: Rect,
201 value_area: Rect,
202 theme: &Theme,
203 info: &PdPortInfo,
204 ) {
205 frame.render_widget(Paragraph::new("Current limit"), key_area);
206 frame.render_widget(
207 Paragraph::new(format!("{} mA", info.current_limit))
208 .style(Style::default().fg(theme.informative_text)),
209 value_area,
210 );
211 }
212
213 fn render_current_max(
214 &self,
215 frame: &mut Frame,
216 key_area: Rect,
217 value_area: Rect,
218 theme: &Theme,
219 info: &PdPortInfo,
220 ) {
221 frame.render_widget(Paragraph::new("Current max"), key_area);
222 frame.render_widget(
223 Paragraph::new(format!("{} mA", info.current_max))
224 .style(Style::default().fg(theme.informative_text)),
225 value_area,
226 );
227 }
228
229 fn render_max_power(
230 &self,
231 frame: &mut Frame,
232 key_area: Rect,
233 value_area: Rect,
234 theme: &Theme,
235 info: &PdPortInfo,
236 ) {
237 frame.render_widget(Paragraph::new("Max power"), key_area);
238 frame.render_widget(
239 Paragraph::new(format!(
240 "{}.{} W",
241 info.max_power / 1000,
242 info.max_power % 1000
243 ))
244 .style(Style::default().fg(theme.informative_text)),
245 value_area,
246 );
247 }
248}
249
250impl Component for PdPortsPanelComponent {
251 fn render(&mut self, frame: &mut Frame, area: Rect, theme: &Theme, info: &FrameworkInfo) {
252 let block = Block::default()
253 .title(" PD ports ")
254 .borders(Borders::ALL)
255 .border_style(Style::default().fg(theme.border))
256 .border_type(BorderType::Rounded);
257
258 let [left_area, right_area] =
259 Layout::horizontal([Constraint::Fill(1), Constraint::Fill(1)]).areas(block.inner(area));
260
261 let [left_back_area, left_front_area] =
262 Layout::vertical([Constraint::Min(5), Constraint::Min(0)])
263 .margin(1)
264 .areas(left_area);
265 let [right_back_area, right_front_area] =
266 Layout::vertical([Constraint::Min(5), Constraint::Min(0)])
267 .margin(1)
268 .areas(right_area);
269
270 self.render_port_block(
271 frame,
272 left_back_area,
273 "Left back",
274 theme,
275 &info.pd_ports.left_back,
276 );
277 self.render_port_block(
278 frame,
279 left_front_area,
280 "Left front",
281 theme,
282 &info.pd_ports.left_front,
283 );
284 self.render_port_block(
285 frame,
286 right_back_area,
287 "Right back",
288 theme,
289 &info.pd_ports.right_back,
290 );
291 self.render_port_block(
292 frame,
293 right_front_area,
294 "Right front",
295 theme,
296 &info.pd_ports.right_front,
297 );
298
299 frame.render_widget(block, area);
300 }
301}