datui_lib/widgets/ui/
working.rs1use crate::render::context::RenderContext;
5use ratatui::buffer::Buffer;
6use ratatui::layout::Rect;
7use ratatui::style::{Modifier, Style};
8use ratatui::text::{Line, Span};
9use ratatui::widgets::{Clear, Paragraph, Widget};
10
11#[derive(Clone, Copy)]
12pub struct Working<'a> {
13 pub text: &'a str,
14 pub frame: usize,
16}
17
18impl Working<'_> {
19 pub fn line(&self, ctx: &RenderContext) -> Line<'static> {
20 let g = crate::glyphs::get();
21 Line::from(vec![
22 Span::styled(
23 format!("{} ", g.spinner[self.frame % g.spinner.len()]),
24 Style::default().fg(ctx.throbber),
25 ),
26 Span::styled(
27 self.text.to_string(),
28 Style::default()
29 .fg(ctx.text_primary)
30 .add_modifier(Modifier::BOLD),
31 ),
32 ])
33 }
34
35 pub fn render_centered(&self, area: Rect, buf: &mut Buffer, ctx: &RenderContext) {
38 Clear.render(area, buf);
39 if area.height == 0 {
40 return;
41 }
42 let y = area.y + (area.height / 2).saturating_sub(1);
43 Paragraph::new(self.line(ctx)).centered().render(
44 Rect {
45 y,
46 height: 1,
47 ..area
48 },
49 buf,
50 );
51 }
52
53 pub fn render_corner(&self, area: Rect, buf: &mut Buffer, ctx: &RenderContext) {
56 let line = self.line(ctx);
57 let width = (line.width() as u16 + 2).min(area.width);
59 if area.height == 0 || width == 0 {
60 return;
61 }
62 let spot = Rect {
63 x: area.right() - width,
64 y: area.y,
65 width,
66 height: 1,
67 };
68 Clear.render(spot, buf);
69 Paragraph::new(line).centered().render(spot, buf);
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 fn text(buf: &Buffer) -> Vec<String> {
78 let w = buf.area.width as usize;
79 buf.content()
80 .chunks(w)
81 .map(|row| row.iter().map(|c| c.symbol()).collect())
82 .collect()
83 }
84
85 #[test]
86 fn centered_replaces_what_was_there() {
87 let ctx = RenderContext::for_test();
88 let area = Rect::new(0, 0, 30, 5);
89 let mut buf = Buffer::empty(area);
90 Paragraph::new(vec![Line::from("old"); 5]).render(area, &mut buf);
91 Working {
92 text: "Applying SQL query...",
93 frame: 0,
94 }
95 .render_centered(area, &mut buf, &ctx);
96 let rows = text(&buf);
97 assert!(rows[1].contains("Applying SQL query..."), "{rows:#?}");
98 assert!(rows.iter().all(|row| !row.contains("old")), "{rows:#?}");
99 }
100
101 #[test]
102 fn corner_keeps_what_is_under_it() {
103 let ctx = RenderContext::for_test();
104 let area = Rect::new(0, 0, 40, 3);
105 let mut buf = Buffer::empty(area);
106 Paragraph::new(vec![Line::from("chart"); 3]).render(area, &mut buf);
107 Working {
108 text: "Computing...",
109 frame: 0,
110 }
111 .render_corner(area, &mut buf, &ctx);
112 let rows = text(&buf);
113 assert!(rows[0].trim_end().ends_with("Computing..."), "{rows:#?}");
114 assert!(rows.iter().all(|row| row.starts_with("chart")), "{rows:#?}");
115 }
116}