tui_realm_stdlib/components/
label.rs

1//! ## Label
2//!
3//! `Label` represents a read-only text component without any container.
4
5use tuirealm::command::{Cmd, CmdResult};
6use tuirealm::props::{Alignment, AttrValue, Attribute, Color, Props, Style, TextModifiers};
7use tuirealm::ratatui::{layout::Rect, widgets::Paragraph};
8use tuirealm::{Frame, MockComponent, State};
9
10// -- Component
11
12/// ## Label
13///
14/// represents a read-only text component without any container.
15#[derive(Default)]
16#[must_use]
17pub struct Label {
18    props: Props,
19}
20
21impl Label {
22    pub fn foreground(mut self, fg: Color) -> Self {
23        self.attr(Attribute::Foreground, AttrValue::Color(fg));
24        self
25    }
26
27    pub fn background(mut self, bg: Color) -> Self {
28        self.attr(Attribute::Background, AttrValue::Color(bg));
29        self
30    }
31
32    pub fn modifiers(mut self, m: TextModifiers) -> Self {
33        self.attr(Attribute::TextProps, AttrValue::TextModifiers(m));
34        self
35    }
36
37    pub fn text<S: Into<String>>(mut self, t: S) -> Self {
38        self.attr(Attribute::Text, AttrValue::String(t.into()));
39        self
40    }
41
42    pub fn alignment(mut self, alignment: Alignment) -> Self {
43        self.attr(Attribute::Alignment, AttrValue::Alignment(alignment));
44        self
45    }
46}
47
48impl MockComponent for Label {
49    fn view(&mut self, render: &mut Frame, area: Rect) {
50        // Make a Span
51        if self.props.get_or(Attribute::Display, AttrValue::Flag(true)) == AttrValue::Flag(true) {
52            // Make text
53            let text = self
54                .props
55                .get_ref(Attribute::Text)
56                .and_then(|v| v.as_string())
57                .map_or("", |v| v.as_str());
58            let foreground = self
59                .props
60                .get_or(Attribute::Foreground, AttrValue::Color(Color::Reset))
61                .unwrap_color();
62            let background = self
63                .props
64                .get_or(Attribute::Background, AttrValue::Color(Color::Reset))
65                .unwrap_color();
66            let alignment: Alignment = self
67                .props
68                .get_or(Attribute::Alignment, AttrValue::Alignment(Alignment::Left))
69                .unwrap_alignment();
70            let modifiers = self
71                .props
72                .get_or(
73                    Attribute::TextProps,
74                    AttrValue::TextModifiers(TextModifiers::empty()),
75                )
76                .unwrap_text_modifiers();
77            render.render_widget(
78                Paragraph::new(text)
79                    .style(
80                        Style::default()
81                            .fg(foreground)
82                            .bg(background)
83                            .add_modifier(modifiers),
84                    )
85                    .alignment(alignment),
86                area,
87            );
88        }
89    }
90
91    fn query(&self, attr: Attribute) -> Option<AttrValue> {
92        self.props.get(attr)
93    }
94
95    fn attr(&mut self, attr: Attribute, value: AttrValue) {
96        self.props.set(attr, value);
97    }
98
99    fn state(&self) -> State {
100        State::None
101    }
102
103    fn perform(&mut self, _cmd: Cmd) -> CmdResult {
104        CmdResult::None
105    }
106}
107
108#[cfg(test)]
109mod tests {
110
111    use super::*;
112
113    use pretty_assertions::assert_eq;
114
115    #[test]
116    fn test_components_label() {
117        let component: Label = Label::default()
118            .alignment(Alignment::Center)
119            .background(Color::Red)
120            .foreground(Color::Yellow)
121            .modifiers(TextModifiers::BOLD)
122            .text("foobar");
123
124        assert_eq!(component.state(), State::None);
125    }
126
127    #[test]
128    fn test_various_text_inputs() {
129        let _ = Label::default().text("str");
130        let _ = Label::default().text(String::from("String"));
131        // explicitly test references to string working
132        #[allow(clippy::needless_borrows_for_generic_args)]
133        let _ = Label::default().text(&String::from("&String"));
134    }
135}