framework_tool_tui/tui/component/
brightness_panel.rs1use std::sync::Arc;
2
3use ratatui::{
4 crossterm::event::{Event, KeyCode, KeyEventKind},
5 layout::{Constraint, Layout, Rect},
6 prelude::*,
7 style::Styled,
8 widgets::{Block, BorderType, Borders, Gauge, Paragraph},
9 Frame,
10};
11
12use crate::{
13 app::AppEvent,
14 framework::{
15 fingerprint::{led_brightness_percentage_to_level_name, Fingerprint},
16 info::FrameworkInfo,
17 },
18 tui::{
19 component::{AdjustableComponent, AdjustablePanel, Component},
20 control::{percentage_control, AdjustableControl},
21 theme::Theme,
22 },
23};
24
25const FINGERPRINT_BRIGHTNESS_CONTROL_INDEX: usize = 0;
26const KEYBOARD_BRIGHTNESS_CONTROL_INDEX: usize = 1;
27
28pub struct BrightnessPanelComponent {
29 panel: AdjustablePanel,
30 fingerprint: Arc<Fingerprint>,
31}
32
33impl BrightnessPanelComponent {
34 pub fn new(fingerprint: Arc<Fingerprint>) -> Self {
35 let panel = AdjustablePanel {
36 selected: false,
37 controls: vec![percentage_control(0), percentage_control(0)],
38 selected_control: FINGERPRINT_BRIGHTNESS_CONTROL_INDEX,
39 };
40
41 Self { panel, fingerprint }
42 }
43
44 fn render_fp_brightness(
45 &mut self,
46 frame: &mut Frame,
47 key_area: Rect,
48 value_area: Rect,
49 theme: &Theme,
50 info: &FrameworkInfo,
51 ) {
52 let style = self.panel.adjustable_control_style(
53 Style::new().fg(theme.background).bg(theme.text),
54 Style::default(),
55 FINGERPRINT_BRIGHTNESS_CONTROL_INDEX,
56 );
57
58 let fp_brightness_percentage = if self
59 .panel
60 .is_panel_selected_and_control_focused_by_index(FINGERPRINT_BRIGHTNESS_CONTROL_INDEX)
61 {
62 self.panel.get_selected_control().get_percentage_value()
63 } else if let Some(value) = info.fp_brightness_percentage {
64 self.panel.set_percentage_control_by_index(
65 FINGERPRINT_BRIGHTNESS_CONTROL_INDEX,
66 percentage_control(value),
67 );
68
69 Some(value)
70 } else {
71 None
72 };
73
74 let gauge = match fp_brightness_percentage {
75 Some(fp_brightness_percentage) => {
76 let style = self.panel.adjustable_control_style(
77 Style::default().fg(theme.text).bg(theme.background),
78 Style::default()
79 .fg(theme.brightness_bar)
80 .bg(theme.bar_background),
81 FINGERPRINT_BRIGHTNESS_CONTROL_INDEX,
82 );
83 let level_name = led_brightness_percentage_to_level_name(fp_brightness_percentage);
84 let label = if self.panel.is_panel_selected_and_control_focused_by_index(
85 FINGERPRINT_BRIGHTNESS_CONTROL_INDEX,
86 ) {
87 format!("◀ {} {:3}% ▶", level_name, fp_brightness_percentage)
88 } else {
89 format!("{} {:3}%", level_name, fp_brightness_percentage)
90 };
91
92 Gauge::default()
93 .percent(fp_brightness_percentage as u16)
94 .label(label)
95 .gauge_style(style)
96 }
97 None => Gauge::default().percent(0).label("N/A").gauge_style(style),
98 };
99
100 frame.render_widget(
101 Paragraph::new("Fingerprint brightness").set_style(style),
102 key_area,
103 );
104 frame.render_widget(gauge, value_area);
105 }
106
107 fn render_kb_brightness(
108 &mut self,
109 frame: &mut Frame,
110 key_area: Rect,
111 value_area: Rect,
112 theme: &Theme,
113 info: &FrameworkInfo,
114 ) {
115 let style = self.panel.adjustable_control_style(
116 Style::new().fg(theme.background).bg(theme.text),
117 Style::default(),
118 KEYBOARD_BRIGHTNESS_CONTROL_INDEX,
119 );
120
121 let kb_brightness_percentage = if self
122 .panel
123 .is_panel_selected_and_control_focused_by_index(KEYBOARD_BRIGHTNESS_CONTROL_INDEX)
124 {
125 self.panel.get_selected_control().get_percentage_value()
126 } else if let Some(value) = info.kb_brightness_percentage {
127 self.panel.set_percentage_control_by_index(
128 KEYBOARD_BRIGHTNESS_CONTROL_INDEX,
129 percentage_control(value),
130 );
131
132 Some(value)
133 } else {
134 None
135 };
136
137 let gauge = match kb_brightness_percentage {
138 Some(kb_brightness_percentage) => {
139 let style = self.panel.adjustable_control_style(
140 Style::default().fg(theme.text).bg(theme.background),
141 Style::default()
142 .fg(theme.brightness_bar)
143 .bg(theme.bar_background),
144 KEYBOARD_BRIGHTNESS_CONTROL_INDEX,
145 );
146 let label = if self.panel.is_panel_selected_and_control_focused_by_index(
147 KEYBOARD_BRIGHTNESS_CONTROL_INDEX,
148 ) {
149 format!("◀ {:3}% ▶", kb_brightness_percentage)
150 } else {
151 format!("{:3}%", kb_brightness_percentage)
152 };
153
154 Gauge::default()
155 .percent(kb_brightness_percentage as u16)
156 .label(label)
157 .gauge_style(style)
158 }
159 None => Gauge::default().percent(0).label("N/A").gauge_style(style),
160 };
161
162 frame.render_widget(
163 Paragraph::new("Keyboard brightness").set_style(style),
164 key_area,
165 );
166 frame.render_widget(gauge, value_area);
167 }
168
169 fn adjust_focused_fp_brightness_control(&mut self, delta: i8) {
170 if let Some(AdjustableControl::Percentage(focused, value)) =
171 self.panel.get_selected_and_focused_control()
172 {
173 let new_value = self
174 .fingerprint
175 .adjust_led_brightness_by_delta(*value, delta);
176
177 if (0..=100).contains(&new_value) {
178 self.panel.controls[self.panel.selected_control] =
179 AdjustableControl::Percentage(*focused, new_value);
180 }
181 }
182 }
183}
184
185impl AdjustableComponent for BrightnessPanelComponent {
186 fn panel(&mut self) -> &mut AdjustablePanel {
187 &mut self.panel
188 }
189}
190
191impl Component for BrightnessPanelComponent {
192 fn handle_input(&mut self, event: Event) -> Option<crate::app::AppEvent> {
193 let mut app_event = None;
194
195 if self.panel.is_selected() {
196 if let Event::Key(key) = event {
197 if key.kind == KeyEventKind::Press {
198 match key.code {
199 KeyCode::Down => self.panel.cycle_controls_down(),
200 KeyCode::Up => self.panel.cycle_controls_up(),
201 KeyCode::Enter => {
202 match self.panel.get_selected_and_focused_control() {
203 Some(control)
204 if self.panel.selected_control
205 == FINGERPRINT_BRIGHTNESS_CONTROL_INDEX =>
206 {
207 if let Some(value) = control.get_percentage_value() {
208 app_event = Some(AppEvent::SetFingerprintBrightness(value));
209 }
210 }
211 Some(control)
212 if self.panel.selected_control
213 == KEYBOARD_BRIGHTNESS_CONTROL_INDEX =>
214 {
215 if let Some(value) = control.get_percentage_value() {
216 app_event = Some(AppEvent::SetKeyboardBrightness(value));
217 }
218 }
219 _ => {}
220 }
221
222 self.panel.toggle_selected_control_focus()
223 }
224 KeyCode::Left => {
225 if self.panel.selected_control == KEYBOARD_BRIGHTNESS_CONTROL_INDEX {
226 self.panel.adjust_focused_percentage_control_by_delta(-5)
227 } else {
228 self.adjust_focused_fp_brightness_control(-5);
229 }
230 }
231 KeyCode::Right => {
232 if self.panel.selected_control == KEYBOARD_BRIGHTNESS_CONTROL_INDEX {
233 self.panel.adjust_focused_percentage_control_by_delta(5)
234 } else {
235 self.adjust_focused_fp_brightness_control(5);
236 }
237 }
238 KeyCode::Esc => self.panel.toggle_selected_control_focus(),
239 _ => {}
240 }
241 }
242 }
243 }
244
245 app_event
246 }
247
248 fn render(&mut self, frame: &mut Frame, area: Rect, theme: &Theme, info: &FrameworkInfo) {
249 let block = Block::default()
250 .title(" Brightness ")
251 .borders(Borders::ALL)
252 .border_type(BorderType::Rounded)
253 .border_style(self.panel.borders_style(theme));
254
255 let [keys_area, values_area] =
256 Layout::horizontal([Constraint::Fill(1), Constraint::Fill(1)])
257 .horizontal_margin(2)
258 .vertical_margin(1)
259 .areas(block.inner(area));
260
261 let keys_block = Block::default().borders(Borders::NONE);
262 let values_block = Block::default().borders(Borders::NONE);
263
264 let [fp_brightness_key_area, kb_brightness_key_area] =
265 Layout::vertical([Constraint::Length(1), Constraint::Length(1)])
266 .spacing(1)
267 .areas(keys_block.inner(keys_area));
268 let [fp_brightness_value_area, kb_brightness_value_area] =
269 Layout::vertical([Constraint::Length(1), Constraint::Length(1)])
270 .spacing(1)
271 .horizontal_margin(1)
272 .areas(values_block.inner(values_area));
273
274 self.render_fp_brightness(
276 frame,
277 fp_brightness_key_area,
278 fp_brightness_value_area,
279 theme,
280 info,
281 );
282
283 self.render_kb_brightness(
285 frame,
286 kb_brightness_key_area,
287 kb_brightness_value_area,
288 theme,
289 info,
290 );
291
292 frame.render_widget(keys_block, keys_area);
294 frame.render_widget(values_block, values_area);
295
296 frame.render_widget(block, area);
297 }
298}