retroglyph_widgets/widget/
text.rs1use retroglyph_core::{Backend, Rect, Style, Terminal};
3use unicode_width::UnicodeWidthStr;
4
5use super::Widget;
6use crate::Align;
7use crate::text::truncate as truncate_to_cols;
8
9#[derive(Clone, Copy, Debug)]
21pub struct Text<'a> {
22 content: &'a str,
23 style: Style,
24 align: Align,
25}
26
27impl<'a> Text<'a> {
28 #[must_use]
30 pub fn new(content: &'a str) -> Self {
31 Self {
32 content,
33 style: Style::new(),
34 align: Align::Left,
35 }
36 }
37
38 #[must_use]
40 pub const fn style(mut self, style: Style) -> Self {
41 self.style = style;
42 self
43 }
44
45 #[must_use]
47 pub const fn align(mut self, align: Align) -> Self {
48 self.align = align;
49 self
50 }
51}
52
53impl<B: Backend> Widget<B> for Text<'_> {
54 fn render(self, area: Rect, term: &mut Terminal<B>) {
55 if area.width() == 0 {
56 return;
57 }
58 let text = truncate_to_cols(self.content, area.width_usize());
59 let x = area.left() + self.align.offset(area.width(), text.width() as u16);
60 term.reset_style()
61 .fg(self.style.foreground())
62 .bg(self.style.background());
63 term.print(x, area.top(), &text);
64 term.reset_style();
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use retroglyph_core::{Color, Headless};
71
72 use super::*;
73
74 #[test]
75 fn prints_the_content_in_the_given_style() {
76 let area = Rect::new(0, 0, 10, 1);
77 let mut term = Terminal::new(Headless::new(10, 1));
78 Text::new("hi")
79 .style(Style::new().fg(Color::WHITE))
80 .render(area, &mut term);
81
82 assert_eq!(term.grid().get(0, 0).glyph(), 'h');
83 assert_eq!(term.grid().get(1, 0).glyph(), 'i');
84 assert_eq!(term.grid().get(0, 0).style().foreground(), Color::WHITE);
85 }
86
87 #[test]
88 fn clips_to_area_width() {
89 let area = Rect::new(0, 0, 5, 1);
90 let mut term = Terminal::new(Headless::new(5, 1));
91 Text::new("a much longer message than fits").render(area, &mut term);
92
93 assert_eq!(term.grid().get(4, 0).glyph(), 'c'); }
95
96 #[test]
97 fn right_align_places_text_against_the_right_edge() {
98 let area = Rect::new(0, 0, 10, 1);
99 let mut term = Terminal::new(Headless::new(10, 1));
100 Text::new("hi").align(Align::Right).render(area, &mut term);
101
102 assert_eq!(term.grid().get(8, 0).glyph(), 'h');
104 assert_eq!(term.grid().get(9, 0).glyph(), 'i');
105 assert_eq!(term.grid().get(7, 0).glyph(), ' ');
106 }
107
108 #[test]
109 fn center_align_centers_text() {
110 let area = Rect::new(0, 0, 10, 1);
111 let mut term = Terminal::new(Headless::new(10, 1));
112 Text::new("hi").align(Align::Center).render(area, &mut term);
113
114 assert_eq!(term.grid().get(4, 0).glyph(), 'h');
116 assert_eq!(term.grid().get(5, 0).glyph(), 'i');
117 }
118
119 #[test]
120 fn zero_width_is_a_no_op() {
121 let area = Rect::new(0, 0, 0, 1);
122 let mut term = Terminal::new(Headless::new(1, 1));
123 Text::new("hi").render(area, &mut term);
124 assert_eq!(term.grid().get(0, 0).glyph(), ' ');
125 }
126}