saorsa_core/widget/
static_widget.rs1use crate::buffer::ScreenBuffer;
4use crate::cell::Cell;
5use crate::geometry::Rect;
6use crate::segment::Segment;
7
8use super::Widget;
9
10#[derive(Clone, Debug)]
14pub struct StaticWidget {
15 lines: Vec<Segment>,
16}
17
18impl StaticWidget {
19 pub fn new(lines: Vec<Segment>) -> Self {
21 Self { lines }
22 }
23
24 pub fn from_segment(segment: Segment) -> Self {
26 Self {
27 lines: vec![segment],
28 }
29 }
30
31 pub fn lines(&self) -> &[Segment] {
33 &self.lines
34 }
35}
36
37impl Widget for StaticWidget {
38 fn render(&self, area: Rect, buf: &mut ScreenBuffer) {
39 if area.size.width == 0 || area.size.height == 0 {
40 return;
41 }
42
43 for (row, segment) in self.lines.iter().enumerate() {
44 let y = area.position.y + row as u16;
45 if y >= area.position.y + area.size.height {
46 break;
47 }
48
49 let mut col: u16 = 0;
50 for ch in segment.text.chars() {
51 let x = area.position.x + col;
52 if x >= area.position.x + area.size.width {
53 break;
54 }
55 let ch_width = unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0);
56 buf.set(x, y, Cell::new(ch.to_string(), segment.style.clone()));
57 col += ch_width as u16;
58 }
59 }
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66 use crate::color::{Color, NamedColor};
67 use crate::geometry::Size;
68 use crate::style::Style;
69
70 #[test]
71 fn single_line() {
72 let seg = Segment::new("hello");
73 let w = StaticWidget::from_segment(seg);
74 let mut buf = ScreenBuffer::new(Size::new(10, 3));
75 w.render(Rect::new(0, 0, 10, 3), &mut buf);
76 assert_eq!(buf.get(0, 0).map(|c| c.grapheme.as_str()), Some("h"));
77 assert_eq!(buf.get(4, 0).map(|c| c.grapheme.as_str()), Some("o"));
78 }
79
80 #[test]
81 fn multi_line() {
82 let lines = vec![Segment::new("line1"), Segment::new("line2")];
83 let w = StaticWidget::new(lines);
84 let mut buf = ScreenBuffer::new(Size::new(10, 5));
85 w.render(Rect::new(0, 0, 10, 5), &mut buf);
86 assert_eq!(buf.get(0, 0).map(|c| c.grapheme.as_str()), Some("l"));
87 assert_eq!(buf.get(0, 1).map(|c| c.grapheme.as_str()), Some("l"));
88 assert_eq!(buf.get(4, 1).map(|c| c.grapheme.as_str()), Some("2"));
89 }
90
91 #[test]
92 fn styled_segment() {
93 let style = Style::new().fg(Color::Named(NamedColor::Green));
94 let seg = Segment::styled("X", style.clone());
95 let w = StaticWidget::from_segment(seg);
96 let mut buf = ScreenBuffer::new(Size::new(5, 1));
97 w.render(Rect::new(0, 0, 5, 1), &mut buf);
98 assert_eq!(buf.get(0, 0).map(|c| &c.style), Some(&style));
99 }
100
101 #[test]
102 fn truncates_to_area_width() {
103 let seg = Segment::new("very long text here");
104 let w = StaticWidget::from_segment(seg);
105 let mut buf = ScreenBuffer::new(Size::new(5, 1));
106 w.render(Rect::new(0, 0, 5, 1), &mut buf);
107 assert_eq!(buf.get(4, 0).map(|c| c.grapheme.as_str()), Some(" "));
109 }
110
111 #[test]
112 fn truncates_to_area_height() {
113 let lines = vec![Segment::new("a"), Segment::new("b"), Segment::new("c")];
114 let w = StaticWidget::new(lines);
115 let mut buf = ScreenBuffer::new(Size::new(5, 2));
116 w.render(Rect::new(0, 0, 5, 2), &mut buf);
117 assert_eq!(buf.get(0, 0).map(|c| c.grapheme.as_str()), Some("a"));
118 assert_eq!(buf.get(0, 1).map(|c| c.grapheme.as_str()), Some("b"));
119 }
121
122 #[test]
123 fn empty_area() {
124 let w = StaticWidget::from_segment(Segment::new("x"));
125 let mut buf = ScreenBuffer::new(Size::new(10, 10));
126 w.render(Rect::new(0, 0, 0, 0), &mut buf);
127 }
129}