1use ratatui::{
2 layout::Alignment,
3 prelude::*,
4 style::{Color, Style},
5 widgets::{Block, Borders, Paragraph, *},
6 Frame,
7};
8
9use crate::app::App;
10
11impl App {
13 pub fn render(&self, frame: &mut Frame) {
14 let &(start_line, start_offset) = self.line_index.get(self.sample_start_index).unwrap();
15 let &(cur_line, cur_offset) = self.line_index.get(self.sample_start_index + self.text.cur_char).unwrap();
16 let &(end_line, end_offset) = self.line_index.get(self.sample_start_index + self.sample_len).unwrap();
17 let mut lines: Vec<String> = self.book_lines.clone();
18 let num_rows = frame.area().height as usize - 2; let rows_to_center = num_rows / 2 - 2; let first_row = usize::checked_sub(rows_to_center, self.display_line).unwrap_or(0);
22
23 let num_skipped_lines = usize::checked_sub(self.display_line, rows_to_center).unwrap_or(0);
24 lines = lines.split_off(usize::min(num_skipped_lines, lines.len()));
25 lines.truncate(num_rows - first_row);
26
27 let mut display_lines: Vec<Line> = Vec::new();
28 for (mut i, s) in lines.iter().enumerate() {
29 i += num_skipped_lines;
30 match i {
31 _ if i == cur_line => match (i == start_line, i == end_line) {
32 (true, true) => {
33 display_lines.push(Line::from(vec![
34 s.chars().take(start_offset).collect::<String>().dim(),
35 s.chars().take(cur_offset).skip(start_offset).collect::<String>().white(),
36 s.chars().nth(cur_offset).unwrap().to_string().black().bg(Color::White),
37 s.chars().take(end_offset).skip(cur_offset + 1).collect::<String>().blue(),
38 s.chars().skip(end_offset).collect::<String>().dim(),
39 ]));
40 }
41 (true, false) => {
42 display_lines.push(Line::from(vec![
43 s.chars().take(start_offset).collect::<String>().dim(),
44 s.chars().take(cur_offset).skip(start_offset).collect::<String>().white(),
45 s.chars().nth(cur_offset).unwrap().to_string().black().bg(Color::White),
46 s.chars().skip(cur_offset + 1).collect::<String>().blue(),
47 ]));
48 }
49 (false, true) => {
50 display_lines.push(Line::from(vec![
51 s.chars().take(cur_offset).collect::<String>().white(),
52 s.chars().nth(cur_offset).unwrap().to_string().black().bg(Color::White),
53 s.chars().take(end_offset).skip(cur_offset + 1).collect::<String>().blue(),
54 s.chars().skip(end_offset).collect::<String>().dim(),
55 ]));
56 }
57 (false, false) => {
58 display_lines.push(Line::from(vec![
59 s.chars().take(cur_offset).collect::<String>().white(),
60 s.chars().nth(cur_offset).unwrap().to_string().black().bg(Color::White),
61 s.chars().skip(cur_offset + 1).collect::<String>().blue(),
62 ]));
63 }
64 },
65 _ if i < cur_line => match i {
66 _ if i == start_line => {
67 display_lines.push(Line::from(vec![
68 s.chars().take(start_offset).collect::<String>().dim(),
69 s.chars().skip(start_offset).collect::<String>().white(),
70 ]));
71 }
72 _ if i < start_line => {
73 display_lines.push(s.clone().dim().into());
74 }
75 _ => {
76 display_lines.push(s.clone().white().into());
77 }
78 },
79 _ if i == end_line => {
80 display_lines.push(Line::from(vec![
81 s.chars().take(end_offset).collect::<String>().blue(),
82 s.chars().skip(end_offset).collect::<String>().dim(),
83 ]));
84 }
85 _ if i < end_line => {
86 display_lines.push(s.clone().blue().into());
87 }
88 _ => {
89 display_lines.push(s.clone().dim().into());
90 }
91 }
92 }
93
94 let graph = Paragraph::new::<Text>(display_lines.into()).style(Style::default());
95
96 let screen = Rect::new(0, 0, frame.area().width, frame.area().height);
97
98 let vert = Layout::default()
99 .direction(Direction::Vertical)
100 .constraints([Constraint::Length(first_row as u16 + 1), Constraint::Percentage(100)])
101 .split(screen);
102 let horiz = Layout::default()
103 .direction(Direction::Horizontal)
104 .constraints([
105 Constraint::Percentage((100 - self.text_width_percent) / 2),
106 Constraint::Percentage(self.text_width_percent),
107 Constraint::Percentage((100 - self.text_width_percent) / 2),
108 ])
109 .split(vert[1])[1];
110
111 frame.render_widget(graph, horiz);
113 frame.render_widget(
114 Block::default()
115 .title("Booktyping")
116 .title(block::Title::from(format!("{}", self.get_rolling_average().unwrap())).alignment(Alignment::Right))
117 .borders(Borders::ALL)
118 .border_style(Style::new().white()),
119 screen,
120 );
121 }
122}