fresh/view/
event_debug.rs1use crate::app::event_debug::EventDebug;
6use crate::view::theme::Theme;
7use ratatui::{
8 layout::{Constraint, Layout, Rect},
9 style::{Modifier, Style},
10 text::{Line, Span},
11 widgets::{Block, Borders, Clear, Paragraph, Wrap},
12 Frame,
13};
14use rust_i18n::t;
15
16const DIALOG_WIDTH: u16 = 70;
18const DIALOG_HEIGHT: u16 = 18;
20
21pub fn render_event_debug(frame: &mut Frame, area: Rect, debug: &EventDebug, theme: &Theme) {
23 let dialog_height = DIALOG_HEIGHT.min(area.height.saturating_sub(4));
25 let dialog_width = DIALOG_WIDTH.min(area.width.saturating_sub(4));
26
27 let dialog_x = area.x + (area.width.saturating_sub(dialog_width)) / 2;
32 let dialog_y = area.y + (area.height.saturating_sub(dialog_height)) / 2;
33
34 let dialog_area = Rect {
35 x: dialog_x,
36 y: dialog_y,
37 width: dialog_width,
38 height: dialog_height,
39 };
40
41 frame.render_widget(Clear, dialog_area);
43
44 let block = Block::default()
46 .title(t!("event_debug.title").to_string())
47 .borders(Borders::ALL)
48 .border_style(Style::default().fg(theme.editor_fg))
49 .style(Style::default().bg(theme.editor_bg).fg(theme.editor_fg));
50
51 let inner_area = block.inner(dialog_area);
52 frame.render_widget(block, dialog_area);
53
54 let chunks = Layout::vertical([
56 Constraint::Length(3), Constraint::Min(8), Constraint::Length(4), ])
60 .split(inner_area);
61
62 let instructions = vec![
64 Line::from(vec![Span::styled(
65 t!("event_debug.instructions").to_string(),
66 Style::default().add_modifier(Modifier::BOLD),
67 )]),
68 Line::from(t!("event_debug.help_text").to_string()),
69 ];
70
71 let instructions_para = Paragraph::new(instructions)
72 .style(Style::default().fg(theme.editor_fg))
73 .wrap(Wrap { trim: true });
74 frame.render_widget(instructions_para, chunks[0]);
75
76 let mut history_lines: Vec<Line> = Vec::new();
78
79 if debug.history.is_empty() {
80 history_lines.push(Line::from(vec![Span::styled(
81 t!("event_debug.no_events").to_string(),
82 Style::default().fg(theme.line_number_fg),
83 )]));
84 } else {
85 history_lines.push(Line::from(vec![
86 Span::styled(
87 t!("event_debug.recent_events").to_string(),
88 Style::default()
89 .fg(theme.help_key_fg)
90 .add_modifier(Modifier::BOLD),
91 ),
92 Span::raw(format!(" ({})", debug.history.len())),
93 ]));
94 history_lines.push(Line::from(""));
95
96 for (i, recorded) in debug.history.iter().enumerate() {
97 let style = if i == 0 {
98 Style::default()
99 .fg(theme.diagnostic_info_fg)
100 .add_modifier(Modifier::BOLD)
101 } else {
102 Style::default().fg(theme.editor_fg)
103 };
104
105 let prefix = if i == 0 { "> " } else { " " };
106 history_lines.push(Line::from(vec![
107 Span::styled(prefix, style),
108 Span::styled(&recorded.description, style),
109 ]));
110 }
111 }
112
113 let history_para = Paragraph::new(history_lines).style(Style::default().fg(theme.editor_fg));
114 frame.render_widget(history_para, chunks[1]);
115
116 let mut control_lines = vec![Line::from(vec![
118 Span::styled("[q]", Style::default().fg(theme.help_key_fg)),
119 Span::raw(" "),
120 Span::raw(t!("event_debug.close").to_string()),
121 Span::raw(" "),
122 Span::styled("[Esc]", Style::default().fg(theme.help_key_fg)),
123 Span::raw(" "),
124 Span::raw(t!("event_debug.close").to_string()),
125 Span::raw(" "),
126 Span::styled("[c]", Style::default().fg(theme.help_key_fg)),
127 Span::raw(" "),
128 Span::raw(t!("event_debug.clear").to_string()),
129 ])];
130
131 if let Some(details) = debug.last_event_details() {
133 control_lines.push(Line::from(""));
134 control_lines.push(Line::from(vec![Span::styled(
135 details,
136 Style::default().fg(theme.line_number_fg),
137 )]));
138 }
139
140 let controls_para = Paragraph::new(control_lines)
141 .style(Style::default().fg(theme.editor_fg))
142 .wrap(Wrap { trim: true });
143 frame.render_widget(controls_para, chunks[2]);
144}