tui_realm_stdlib/components/
paragraph.rs1use tuirealm::command::{Cmd, CmdResult};
10use tuirealm::props::{
11 Alignment, AttrValue, Attribute, Borders, Color, PropPayload, PropValue, Props, Style,
12 TextModifiers, TextSpan,
13};
14use tuirealm::ratatui::text::Line as Spans;
15use tuirealm::ratatui::{
16 layout::Rect,
17 text::Span,
18 widgets::{Paragraph as TuiParagraph, Wrap},
19};
20use tuirealm::{Frame, MockComponent, State};
21
22#[derive(Default)]
28pub struct Paragraph {
29 props: Props,
30}
31
32impl Paragraph {
33 pub fn foreground(mut self, fg: Color) -> Self {
34 self.attr(Attribute::Foreground, AttrValue::Color(fg));
35 self
36 }
37
38 pub fn background(mut self, bg: Color) -> Self {
39 self.attr(Attribute::Background, AttrValue::Color(bg));
40 self
41 }
42
43 pub fn modifiers(mut self, m: TextModifiers) -> Self {
44 self.attr(Attribute::TextProps, AttrValue::TextModifiers(m));
45 self
46 }
47
48 pub fn borders(mut self, b: Borders) -> Self {
49 self.attr(Attribute::Borders, AttrValue::Borders(b));
50 self
51 }
52
53 pub fn alignment(mut self, a: Alignment) -> Self {
54 self.attr(Attribute::Alignment, AttrValue::Alignment(a));
55 self
56 }
57
58 pub fn title<S: Into<String>>(mut self, t: S, a: Alignment) -> Self {
59 self.attr(Attribute::Title, AttrValue::Title((t.into(), a)));
60 self
61 }
62
63 pub fn text(mut self, s: &[TextSpan]) -> Self {
64 self.attr(
65 Attribute::Text,
66 AttrValue::Payload(PropPayload::Vec(
67 s.iter().cloned().map(PropValue::TextSpan).collect(),
68 )),
69 );
70 self
71 }
72
73 pub fn wrap(mut self, wrap: bool) -> Self {
74 self.attr(Attribute::TextWrap, AttrValue::Flag(wrap));
75 self
76 }
77}
78
79impl MockComponent for Paragraph {
80 fn view(&mut self, render: &mut Frame, area: Rect) {
81 if self.props.get_or(Attribute::Display, AttrValue::Flag(true)) == AttrValue::Flag(true) {
83 let text: Vec<Spans> = match self.props.get(Attribute::Text).map(|x| x.unwrap_payload())
85 {
86 Some(PropPayload::Vec(spans)) => spans
87 .iter()
88 .cloned()
89 .map(|x| x.unwrap_text_span())
90 .map(|x| {
91 let (fg, bg, modifiers) =
92 crate::utils::use_or_default_styles(&self.props, &x);
93 Spans::from(vec![Span::styled(
94 x.content,
95 Style::default().add_modifier(modifiers).fg(fg).bg(bg),
96 )])
97 })
98 .collect(),
99 _ => Vec::new(),
100 };
101 let alignment: Alignment = self
103 .props
104 .get_or(Attribute::Alignment, AttrValue::Alignment(Alignment::Left))
105 .unwrap_alignment();
106 let trim = self
108 .props
109 .get_or(Attribute::TextWrap, AttrValue::Flag(false))
110 .unwrap_flag();
111 let foreground = self
112 .props
113 .get_or(Attribute::Foreground, AttrValue::Color(Color::Reset))
114 .unwrap_color();
115 let background = self
116 .props
117 .get_or(Attribute::Background, AttrValue::Color(Color::Reset))
118 .unwrap_color();
119 let modifiers = self
120 .props
121 .get_or(
122 Attribute::TextProps,
123 AttrValue::TextModifiers(TextModifiers::empty()),
124 )
125 .unwrap_text_modifiers();
126 let borders = self
127 .props
128 .get_or(Attribute::Borders, AttrValue::Borders(Borders::default()))
129 .unwrap_borders();
130 let title = self.props.get(Attribute::Title).map(|x| x.unwrap_title());
131 let div = crate::utils::get_block(borders, title, true, None);
132 render.render_widget(
133 TuiParagraph::new(text)
134 .block(div)
135 .style(
136 Style::default()
137 .fg(foreground)
138 .bg(background)
139 .add_modifier(modifiers),
140 )
141 .alignment(alignment)
142 .wrap(Wrap { trim }),
143 area,
144 );
145 }
146 }
147
148 fn query(&self, attr: Attribute) -> Option<AttrValue> {
149 self.props.get(attr)
150 }
151
152 fn attr(&mut self, attr: Attribute, value: AttrValue) {
153 self.props.set(attr, value)
154 }
155
156 fn state(&self) -> State {
157 State::None
158 }
159
160 fn perform(&mut self, _cmd: Cmd) -> CmdResult {
161 CmdResult::None
162 }
163}
164
165#[cfg(test)]
166mod tests {
167
168 use super::*;
169
170 use pretty_assertions::assert_eq;
171
172 #[test]
173 fn test_components_paragraph() {
174 let component = Paragraph::default()
175 .background(Color::Blue)
176 .foreground(Color::Red)
177 .modifiers(TextModifiers::BOLD)
178 .alignment(Alignment::Center)
179 .text(&[
180 TextSpan::from("Press "),
181 TextSpan::from("<ESC>").fg(Color::Cyan).bold(),
182 TextSpan::from(" to quit"),
183 ])
184 .wrap(true)
185 .title("title", Alignment::Center);
186 assert_eq!(component.state(), State::None);
188 }
189}