Skip to main content

framework_tool_tui/tui/component/
brightness_panel.rs

1use 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        // Fingerprint brightness
275        self.render_fp_brightness(
276            frame,
277            fp_brightness_key_area,
278            fp_brightness_value_area,
279            theme,
280            info,
281        );
282
283        // Keyboard brightness
284        self.render_kb_brightness(
285            frame,
286            kb_brightness_key_area,
287            kb_brightness_value_area,
288            theme,
289            info,
290        );
291
292        // Render blocks
293        frame.render_widget(keys_block, keys_area);
294        frame.render_widget(values_block, values_area);
295
296        frame.render_widget(block, area);
297    }
298}