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