tui_realm_stdlib/components/
span.rs1use tuirealm::command::{Cmd, CmdResult};
2use tuirealm::component::Component;
3use tuirealm::props::{
4 AttrValue, Attribute, Color, HorizontalAlignment, PropPayload, PropValue, Props, QueryResult,
5 SpanStatic, Style, TextModifiers,
6};
7use tuirealm::ratatui::Frame;
8use tuirealm::ratatui::layout::Rect;
9use tuirealm::ratatui::text::{Line, Span as RSpan, Text};
10use tuirealm::ratatui::widgets::Paragraph;
11use tuirealm::state::State;
12
13use crate::prop_ext::CommonProps;
14use crate::utils;
15
16#[derive(Default)]
21#[must_use]
22pub struct Span {
23 common: CommonProps,
24 props: Props,
25}
26
27impl Span {
28 pub fn foreground(mut self, fg: Color) -> Self {
30 self.attr(Attribute::Foreground, AttrValue::Color(fg));
31 self
32 }
33
34 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 {
42 self.attr(Attribute::TextProps, AttrValue::TextModifiers(m));
43 self
44 }
45
46 pub fn style(mut self, style: Style) -> Self {
50 self.attr(Attribute::Style, AttrValue::Style(style));
51 self
52 }
53
54 pub fn alignment_horizontal(mut self, a: HorizontalAlignment) -> Self {
56 self.attr(
57 Attribute::AlignmentHorizontal,
58 AttrValue::AlignmentHorizontal(a),
59 );
60 self
61 }
62
63 pub fn spans<T>(mut self, s: impl IntoIterator<Item = T>) -> Self
65 where
66 T: Into<SpanStatic>,
67 {
68 self.attr(
69 Attribute::Text,
70 AttrValue::Payload(PropPayload::Vec(
71 s.into_iter()
72 .map(Into::into)
73 .map(PropValue::TextSpan)
74 .collect(),
75 )),
76 );
77 self
78 }
79}
80
81impl Component for Span {
82 fn view(&mut self, render: &mut Frame, area: Rect) {
83 if !self.common.display {
84 return;
85 }
86
87 let payload = self.props.get(Attribute::Text).and_then(|x| x.as_payload());
90 let text = match payload {
91 Some(PropPayload::Vec(lines)) => {
92 let lines: Vec<RSpan> = lines
93 .iter()
94 .filter_map(|x| x.as_textspan())
96 .map(utils::borrow_clone_span)
97 .collect();
98 Text::from(Line::from(lines))
99 }
100 _ => Text::default(),
101 };
102 let alignment: HorizontalAlignment = self
104 .props
105 .get(Attribute::AlignmentHorizontal)
106 .and_then(AttrValue::as_alignment_horizontal)
107 .unwrap_or(HorizontalAlignment::Left);
108 render.render_widget(
109 Paragraph::new(text)
110 .alignment(alignment)
111 .style(self.common.style),
112 area,
113 );
114 }
115
116 fn query<'a>(&'a self, attr: Attribute) -> Option<QueryResult<'a>> {
117 if let Some(value) = self.common.get_for_query(attr) {
118 return Some(value);
119 }
120
121 self.props.get_for_query(attr)
122 }
123
124 fn attr(&mut self, attr: Attribute, value: AttrValue) {
125 if let Some(value) = self.common.set(attr, value) {
126 self.props.set(attr, value);
127 }
128 }
129
130 fn state(&self) -> State {
131 State::None
132 }
133
134 fn perform(&mut self, cmd: Cmd) -> CmdResult {
135 CmdResult::Invalid(cmd)
136 }
137}
138
139#[cfg(test)]
140mod tests {
141
142 use pretty_assertions::assert_eq;
143 use tuirealm::props::SpanStatic;
144 use tuirealm::ratatui::style::Stylize;
145
146 use super::*;
147
148 #[test]
149 fn test_components_span() {
150 let component = Span::default()
151 .background(Color::Blue)
152 .foreground(Color::Red)
153 .modifiers(TextModifiers::BOLD)
154 .alignment_horizontal(HorizontalAlignment::Center)
155 .spans([
156 SpanStatic::from("Press "),
157 SpanStatic::from("<ESC>").fg(Color::Cyan).bold(),
158 SpanStatic::from(" to quit"),
159 ]);
160 assert_eq!(component.state(), State::None);
162 }
163
164 #[test]
165 fn various_spans_types() {
166 let _ = Span::default().spans(vec![SpanStatic::raw("hello")]);
168 let _ = Span::default().spans([SpanStatic::raw("hello")]);
170 let _ = Span::default().spans(vec![SpanStatic::raw("hello")].into_boxed_slice());
172 let _ = Span::default().spans(["Hello"].map(SpanStatic::raw));
174 }
175}