Skip to main content

framework_tool_tui/tui/component/
title.rs

1use ratatui::{
2    layout::{Constraint, Layout, Rect},
3    prelude::*,
4    widgets::{Block, BorderType, Borders, Paragraph},
5    Frame,
6};
7
8use crate::{
9    app::APP_TITLE,
10    framework::info::FrameworkInfo,
11    tui::{
12        component::Component,
13        theme::{Theme, ThemeVariant},
14    },
15};
16
17pub struct TitleComponent {
18    theme_name: String,
19    tick_interval_ms: u64,
20}
21
22impl TitleComponent {
23    pub fn new(theme: ThemeVariant) -> Self {
24        Self {
25            theme_name: theme.name().to_string(),
26            tick_interval_ms: 1000,
27        }
28    }
29
30    pub fn set_theme_name(&mut self, name: String) {
31        self.theme_name = name;
32    }
33
34    pub fn set_tick_interval(&mut self, interval_ms: u64) {
35        self.tick_interval_ms = interval_ms;
36    }
37}
38
39impl Component for TitleComponent {
40    fn render(&mut self, frame: &mut Frame, area: Rect, theme: &Theme, info: &FrameworkInfo) {
41        let block = Block::default()
42            .title(APP_TITLE)
43            .borders(Borders::ALL)
44            .border_style(Style::default().fg(theme.border))
45            .border_type(BorderType::Rounded);
46
47        let [smbios_version_area, charging_status_area, charge_percentage_area, max_charge_limit_area, fan_speed_area, theme_area, tick_interval_area] =
48            Layout::horizontal([
49                Constraint::Max(10),
50                Constraint::Max(15),
51                Constraint::Max(6),
52                Constraint::Max(13),
53                Constraint::Min(18),
54                Constraint::Max(30),
55                Constraint::Max(12),
56            ])
57            .spacing(1)
58            .areas(block.inner(area));
59
60        // BIOS version
61        if let Some(smbios_version) = &info.smbios_version {
62            frame.render_widget(
63                Paragraph::new(format!("[ v{} ]", smbios_version))
64                    .style(Style::default().fg(theme.informative_text)),
65                smbios_version_area,
66            );
67        }
68
69        let charge_percentage = info.charge_percentage;
70        let charge_style = match charge_percentage {
71            Some(charge_percentage) if charge_percentage < 15 => {
72                Style::default().fg(theme.indication_warning)
73            }
74            _ => Style::default().fg(theme.indication_ok),
75        };
76
77        // Charging status
78        frame.render_widget(
79            Paragraph::new(format!("[ {}", info.charging_status)).style(charge_style),
80            charging_status_area,
81        );
82
83        // Charge percentage
84        if let Some(charge_percentage) = info.charge_percentage {
85            frame.render_widget(
86                Paragraph::new(format!("{}% ]", charge_percentage)).style(charge_style),
87                charge_percentage_area,
88            );
89        }
90
91        // Max charge limit
92        if let Some(max_charge_limit) = info.max_charge_limit {
93            frame.render_widget(
94                Paragraph::new(format!("[ Max: {}% ]", max_charge_limit))
95                    .style(Style::default().fg(theme.informative_text)),
96                max_charge_limit_area,
97            );
98        }
99
100        // FAN speed
101        if let Some(fan_rpm) = &info.fan_rpm {
102            let text = fan_rpm
103                .iter()
104                .enumerate()
105                .map(|(n, rpm)| format!("FAN{}: {} RPM", n + 1, rpm))
106                .collect::<Vec<String>>()
107                .join(", ");
108
109            frame.render_widget(
110                Paragraph::new(format!("[ {} ]", text))
111                    .style(Style::default().fg(theme.informative_text)),
112                fan_speed_area,
113            );
114        }
115
116        // Theme name
117        if !self.theme_name.is_empty() {
118            frame.render_widget(
119                Paragraph::new(format!("【←b {} n→】", self.theme_name))
120                    .style(Style::default().fg(theme.highlighted_text))
121                    .alignment(Alignment::Right),
122                theme_area,
123            );
124        }
125
126        // Tick interval
127        frame.render_widget(
128            Paragraph::new(format!("- {:4}ms +", self.tick_interval_ms))
129                .style(Style::default().fg(theme.highlighted_text))
130                .alignment(Alignment::Right),
131            tick_interval_area,
132        );
133
134        frame.render_widget(block, area);
135    }
136}