tui_realm_stdlib/components/
span.rs1use tuirealm::command::{Cmd, CmdResult};
7use tuirealm::props::{
8 Alignment, AttrValue, Attribute, Color, PropPayload, PropValue, Props, Style, TextModifiers,
9 TextSpan,
10};
11use tuirealm::ratatui::text::Line as Spans;
12use tuirealm::ratatui::{
13 layout::Rect,
14 text::{Span as TuiSpan, Text},
15 widgets::Paragraph,
16};
17use tuirealm::{Frame, MockComponent, State};
18
19#[derive(Default)]
25pub struct Span {
26 props: Props,
27}
28
29impl Span {
30 pub fn foreground(mut self, fg: Color) -> Self {
31 self.attr(Attribute::Foreground, AttrValue::Color(fg));
32 self
33 }
34
35 pub fn background(mut self, bg: Color) -> Self {
36 self.attr(Attribute::Background, AttrValue::Color(bg));
37 self
38 }
39
40 pub fn modifiers(mut self, m: TextModifiers) -> Self {
41 self.attr(Attribute::TextProps, AttrValue::TextModifiers(m));
42 self
43 }
44
45 pub fn alignment(mut self, a: Alignment) -> Self {
46 self.attr(Attribute::Alignment, AttrValue::Alignment(a));
47 self
48 }
49
50 pub fn spans(mut self, s: &[TextSpan]) -> Self {
51 self.attr(
52 Attribute::Text,
53 AttrValue::Payload(PropPayload::Vec(
54 s.iter().cloned().map(PropValue::TextSpan).collect(),
55 )),
56 );
57 self
58 }
59}
60
61impl MockComponent for Span {
62 fn view(&mut self, render: &mut Frame, area: Rect) {
63 if self.props.get_or(Attribute::Display, AttrValue::Flag(true)) == AttrValue::Flag(true) {
65 let foreground = self
67 .props
68 .get_or(Attribute::Foreground, AttrValue::Color(Color::Reset))
69 .unwrap_color();
70 let background = self
71 .props
72 .get_or(Attribute::Background, AttrValue::Color(Color::Reset))
73 .unwrap_color();
74 let spans: Vec<TuiSpan> =
75 match self.props.get(Attribute::Text).map(|x| x.unwrap_payload()) {
76 Some(PropPayload::Vec(spans)) => spans
77 .iter()
78 .cloned()
79 .map(|x| x.unwrap_text_span())
80 .map(|x| {
81 let (fg, bg, modifiers) =
83 crate::utils::use_or_default_styles(&self.props, &x);
84 TuiSpan::styled(
85 x.content,
86 Style::default().add_modifier(modifiers).fg(fg).bg(bg),
87 )
88 })
89 .collect(),
90 _ => Vec::new(),
91 };
92 let text: Text = Text::from(Spans::from(spans));
93 let alignment: Alignment = self
95 .props
96 .get_or(Attribute::Alignment, AttrValue::Alignment(Alignment::Left))
97 .unwrap_alignment();
98 render.render_widget(
99 Paragraph::new(text)
100 .alignment(alignment)
101 .style(Style::default().bg(background).fg(foreground)),
102 area,
103 );
104 }
105 }
106
107 fn query(&self, attr: Attribute) -> Option<AttrValue> {
108 self.props.get(attr)
109 }
110
111 fn attr(&mut self, attr: Attribute, value: AttrValue) {
112 self.props.set(attr, value)
113 }
114
115 fn state(&self) -> State {
116 State::None
117 }
118
119 fn perform(&mut self, _cmd: Cmd) -> CmdResult {
120 CmdResult::None
121 }
122}
123
124#[cfg(test)]
125mod tests {
126
127 use super::*;
128
129 use pretty_assertions::assert_eq;
130
131 #[test]
132 fn test_components_span() {
133 let component = Span::default()
134 .background(Color::Blue)
135 .foreground(Color::Red)
136 .modifiers(TextModifiers::BOLD)
137 .alignment(Alignment::Center)
138 .spans(&[
139 TextSpan::from("Press "),
140 TextSpan::from("<ESC>").fg(Color::Cyan).bold(),
141 TextSpan::from(" to quit"),
142 ]);
143 assert_eq!(component.state(), State::None);
145 }
146}