1use color_eyre::Result;
17use ratatui::{
18 crossterm::event::{self, Event, KeyCode, KeyEventKind},
19 layout::{Alignment, Constraint, Layout, Rect},
20 style::{Style, Stylize},
21 text::Line,
22 widgets::{Block, BorderType, Borders, Padding, Paragraph, Wrap},
23 DefaultTerminal, Frame,
24};
25
26fn main() -> Result<()> {
27 color_eyre::install()?;
28 let terminal = ratatui::init();
29 let result = run(terminal);
30 ratatui::restore();
31 result
32}
33
34fn run(mut terminal: DefaultTerminal) -> Result<()> {
35 loop {
36 terminal.draw(draw)?;
37 if let Event::Key(key) = event::read()? {
38 if key.kind == KeyEventKind::Press && key.code == KeyCode::Char('q') {
39 break Ok(());
40 }
41 }
42 }
43}
44
45fn draw(frame: &mut Frame) {
46 let (title_area, layout) = calculate_layout(frame.area());
47
48 render_title(frame, title_area);
49
50 let paragraph = placeholder_paragraph();
51
52 render_borders(¶graph, Borders::ALL, frame, layout[0][0]);
53 render_borders(¶graph, Borders::NONE, frame, layout[0][1]);
54 render_borders(¶graph, Borders::LEFT, frame, layout[1][0]);
55 render_borders(¶graph, Borders::RIGHT, frame, layout[1][1]);
56 render_borders(¶graph, Borders::TOP, frame, layout[2][0]);
57 render_borders(¶graph, Borders::BOTTOM, frame, layout[2][1]);
58
59 render_border_type(¶graph, BorderType::Plain, frame, layout[3][0]);
60 render_border_type(¶graph, BorderType::Rounded, frame, layout[3][1]);
61 render_border_type(¶graph, BorderType::Double, frame, layout[4][0]);
62 render_border_type(¶graph, BorderType::Thick, frame, layout[4][1]);
63
64 render_styled_block(¶graph, frame, layout[5][0]);
65 render_styled_borders(¶graph, frame, layout[5][1]);
66 render_styled_title(¶graph, frame, layout[6][0]);
67 render_styled_title_content(¶graph, frame, layout[6][1]);
68 render_multiple_titles(¶graph, frame, layout[7][0]);
69 render_multiple_title_positions(¶graph, frame, layout[7][1]);
70 render_padding(¶graph, frame, layout[8][0]);
71 render_nested_blocks(¶graph, frame, layout[8][1]);
72}
73
74fn calculate_layout(area: Rect) -> (Rect, Vec<Vec<Rect>>) {
78 let main_layout = Layout::vertical([Constraint::Length(1), Constraint::Min(0)]);
79 let block_layout = Layout::vertical([Constraint::Max(4); 9]);
80 let [title_area, main_area] = main_layout.areas(area);
81 let main_areas = block_layout
82 .split(main_area)
83 .iter()
84 .map(|&area| {
85 Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)])
86 .split(area)
87 .to_vec()
88 })
89 .collect();
90 (title_area, main_areas)
91}
92
93fn render_title(frame: &mut Frame, area: Rect) {
94 frame.render_widget(
95 Paragraph::new("Block example. Press q to quit")
96 .dark_gray()
97 .alignment(Alignment::Center),
98 area,
99 );
100}
101
102fn placeholder_paragraph() -> Paragraph<'static> {
103 let text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
104 Paragraph::new(text.dark_gray()).wrap(Wrap { trim: true })
105}
106
107fn render_borders(paragraph: &Paragraph, border: Borders, frame: &mut Frame, area: Rect) {
108 let block = Block::new()
109 .borders(border)
110 .title(format!("Borders::{border:#?}"));
111 frame.render_widget(paragraph.clone().block(block), area);
112}
113
114fn render_border_type(
115 paragraph: &Paragraph,
116 border_type: BorderType,
117 frame: &mut Frame,
118 area: Rect,
119) {
120 let block = Block::bordered()
121 .border_type(border_type)
122 .title(format!("BorderType::{border_type:#?}"));
123 frame.render_widget(paragraph.clone().block(block), area);
124}
125fn render_styled_borders(paragraph: &Paragraph, frame: &mut Frame, area: Rect) {
126 let block = Block::bordered()
127 .border_style(Style::new().blue().on_white().bold().italic())
128 .title("Styled borders");
129 frame.render_widget(paragraph.clone().block(block), area);
130}
131
132fn render_styled_block(paragraph: &Paragraph, frame: &mut Frame, area: Rect) {
133 let block = Block::bordered()
134 .style(Style::new().blue().on_white().bold().italic())
135 .title("Styled block");
136 frame.render_widget(paragraph.clone().block(block), area);
137}
138
139fn render_styled_title(paragraph: &Paragraph, frame: &mut Frame, area: Rect) {
140 let block = Block::bordered()
141 .title("Styled title")
142 .title_style(Style::new().blue().on_white().bold().italic());
143 frame.render_widget(paragraph.clone().block(block), area);
144}
145
146fn render_styled_title_content(paragraph: &Paragraph, frame: &mut Frame, area: Rect) {
147 let title = Line::from(vec![
148 "Styled ".blue().on_white().bold().italic(),
149 "title content".red().on_white().bold().italic(),
150 ]);
151 let block = Block::bordered().title(title);
152 frame.render_widget(paragraph.clone().block(block), area);
153}
154
155fn render_multiple_titles(paragraph: &Paragraph, frame: &mut Frame, area: Rect) {
156 let block = Block::bordered()
157 .title("Multiple".blue().on_white().bold().italic())
158 .title("Titles".red().on_white().bold().italic());
159 frame.render_widget(paragraph.clone().block(block), area);
160}
161
162fn render_multiple_title_positions(paragraph: &Paragraph, frame: &mut Frame, area: Rect) {
163 let block = Block::bordered()
164 .title(Line::from("top left").left_aligned())
165 .title(Line::from("top center").centered())
166 .title(Line::from("top right").right_aligned())
167 .title_bottom(Line::from("bottom left").left_aligned())
168 .title_bottom(Line::from("bottom center").centered())
169 .title_bottom(Line::from("bottom right").right_aligned());
170 frame.render_widget(paragraph.clone().block(block), area);
171}
172
173fn render_padding(paragraph: &Paragraph, frame: &mut Frame, area: Rect) {
174 let block = Block::bordered()
175 .padding(Padding::new(5, 10, 1, 2))
176 .title("Padding");
177 frame.render_widget(paragraph.clone().block(block), area);
178}
179
180fn render_nested_blocks(paragraph: &Paragraph, frame: &mut Frame, area: Rect) {
181 let outer_block = Block::bordered().title("Outer block");
182 let inner_block = Block::bordered().title("Inner block");
183 let inner = outer_block.inner(area);
184 frame.render_widget(outer_block, area);
185 frame.render_widget(paragraph.clone().block(inner_block), inner);
186}