1 use ratatui::{
2 prelude::{Constraint, Layout, Rect},
3 style::{Color, Modifier, Style},
4 symbols,
5 text::{self, Span, Text},
6 widgets::{Block, Borders, List, ListItem, Sparkline, Tabs},
7 Frame,
8 };
9
10 use crate::app::App;
11
12 /// Renders the user interface widgets.
render(app: &mut App, frame: &mut Frame)13 pub fn render(app: &mut App, frame: &mut Frame) {
14 // This is where you add new widgets.
15 // See the following resources:
16 // - https://docs.rs/ratatui/latest/ratatui/widgets/index.html
17 // - https://github.com/ratatui-org/ratatui/tree/master/examples
18 // frame.render_widget(
19 // Paragraph::new(format!(
20 // "This is a tui template.\n\
21 // Press `Esc`, `Ctrl-C` or `q` to stop running.\n\
22 // Press left and right to increment and decrement the counter respectively.\n\
23 // Counter: {}",
24 // app.counter
25 // ))
26 // .block(
27 // Block::default()
28 // .title("Template")
29 // .title_alignment(Alignment::Center)
30 // .borders(Borders::ALL)
31 // .border_type(BorderType::Rounded),
32 // )
33 // .style(Style::default().fg(Color::Cyan).bg(Color::Black))
34 // .alignment(Alignment::Center),
35 // frame.size(),
36 // )
37
38 let chunks = Layout::default()
39 .constraints([Constraint::Length(3), Constraint::Min(0)])
40 .split(frame.size());
41 let titles = app
42 .tabs
43 .titles
44 .iter()
45 .map(|t| text::Line::from(Span::styled(*t, Style::default().fg(Color::Green))))
46 .collect();
47 let tabs = Tabs::new(titles)
48 .block(Block::default().borders(Borders::ALL).title(app.title))
49 .highlight_style(Style::default().fg(Color::Yellow))
50 .select(app.tabs.index);
51 frame.render_widget(tabs, chunks[0]);
52
53 match app.tabs.index {
54 0 => draw_first_tab(frame, app, chunks[1]),
55 _ => {}
56 }
57 }
58
draw_first_tab(f: &mut Frame, app: &mut App, area: Rect)59 fn draw_first_tab(f: &mut Frame, app: &mut App, area: Rect) {
60 let chunks = Layout::default()
61 .constraints([
62 Constraint::Min(1),
63 Constraint::Min(3),
64 Constraint::Length(7),
65 ])
66 .split(area);
67 draw_memory_logging_speed_gauges(f, app, chunks[0]);
68 // draw_charts(f, app, chunks[1]);
69 draw_footer(f, app, chunks[2]);
70 }
71
72 /// 绘制内存日志产生数量的图表
draw_memory_logging_speed_gauges(f: &mut Frame, app: &mut App, area: Rect)73 fn draw_memory_logging_speed_gauges(f: &mut Frame, app: &mut App, area: Rect) {
74 let chunks = Layout::default()
75 .constraints([Constraint::Length(3)])
76 .margin(1)
77 .split(area);
78 let block = Block::default().borders(Borders::ALL).title("Speed:");
79 f.render_widget(block, area);
80
81 let sparkline = Sparkline::default()
82 .block(Block::default().title("Memory Log Speed:"))
83 .style(Style::default().fg(Color::Green))
84 .data(&app.memory_log_sparkline.points)
85 .bar_set(if app.enhanced_graphics {
86 symbols::bar::NINE_LEVELS
87 } else {
88 symbols::bar::THREE_LEVELS
89 });
90 f.render_widget(sparkline, chunks[0]);
91 }
92
draw_footer(f: &mut Frame, app: &mut App, area: Rect)93 fn draw_footer(f: &mut Frame, app: &mut App, area: Rect) {
94 let _block = Block::default().borders(Borders::ALL).title(Span::styled(
95 "Logs",
96 Style::default()
97 .fg(Color::Magenta)
98 .add_modifier(Modifier::BOLD),
99 ));
100
101 let info_style = Style::default().fg(Color::Blue);
102 let warning_style = Style::default().fg(Color::Yellow);
103 let error_style = Style::default().fg(Color::Magenta);
104 let critical_style = Style::default().fg(Color::Red);
105
106 let binding = app.logs().clone();
107 let log_list = binding
108 .iter()
109 .map(|log_str| {
110 let _style = match log_str {
111 log if log.contains("INFO") => info_style,
112 log if log.contains("WARNING") => warning_style,
113 log if log.contains("ERROR") => error_style,
114 log if log.contains("CRITICAL") => critical_style,
115 _ => Style::default().fg(Color::White),
116 };
117
118 // println!("log_str: {}", log_str);
119
120 ListItem::new(Text::from(log_str.clone()))
121 })
122 .collect::<Vec<ListItem>>();
123
124 let items_num = 5;
125 let list_to_show = log_list.split_at(if log_list.len() > items_num {
126 log_list.len() - items_num
127 } else {
128 0
129 });
130
131 let logs =
132 List::new(list_to_show.1).block(Block::default().borders(Borders::ALL).title("List"));
133 f.render_stateful_widget(logs, area, &mut app.stateful_logs.state);
134 }
135