rpi_tui/
truncated_text.rs1use std::any::Any;
6use std::sync::Mutex;
7
8use super::component::Component;
9use crate::utils::{truncate_to_width, visible_width};
10
11pub struct TruncatedText {
13 text: Mutex<String>,
14 max_width: usize,
15 ellipsis: String,
16 style: Option<String>,
17}
18
19impl TruncatedText {
20 pub fn new(text: &str, max_width: usize) -> Self {
22 Self {
23 text: Mutex::new(text.to_string()),
24 max_width,
25 ellipsis: "...".to_string(),
26 style: None,
27 }
28 }
29
30 pub fn with_ellipsis(text: &str, max_width: usize, ellipsis: &str) -> Self {
32 Self {
33 text: Mutex::new(text.to_string()),
34 max_width,
35 ellipsis: ellipsis.to_string(),
36 style: None,
37 }
38 }
39
40 pub fn set_text(&self, text: &str) {
42 if let Ok(mut t) = self.text.lock() {
43 *t = text.to_string();
44 }
45 }
46
47 pub fn get_text(&self) -> String {
49 self.text.lock().map(|t| t.clone()).unwrap_or_default()
50 }
51
52 pub fn set_max_width(&mut self, width: usize) {
54 self.max_width = width;
55 }
56
57 pub fn set_style(&mut self, style: &str) {
59 self.style = Some(style.to_string());
60 }
61
62 pub fn is_truncated(&self) -> bool {
64 let text = self.get_text();
65 visible_width(&text) > self.max_width
66 }
67}
68
69impl Component for TruncatedText {
70 fn render(&self, width: usize) -> Vec<String> {
71 let text = self.get_text();
72 let effective_width = self.max_width.min(width);
73
74 let truncated = truncate_to_width(&text, effective_width, &self.ellipsis);
75
76 let styled = if let Some(ref style) = self.style {
77 format!("{}{}\x1b[0m", style, truncated)
78 } else {
79 truncated
80 };
81
82 vec![styled]
83 }
84
85 fn invalidate(&self) {
86 }
88
89 fn as_any(&self) -> &dyn Any {
90 self
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97
98 #[test]
99 fn test_truncated_text() {
100 let text = TruncatedText::new("Hello World", 5);
101 let lines = text.render(10);
102 assert!(lines[0].contains("H"));
103 }
104
105 #[test]
106 fn test_is_truncated() {
107 let text = TruncatedText::new("Hello World", 5);
108 assert!(text.is_truncated());
109 }
110
111 #[test]
112 fn test_not_truncated() {
113 let text = TruncatedText::new("Hi", 10);
114 assert!(!text.is_truncated());
115 }
116}