tui_realm_stdlib/components/
container.rs1use tuirealm::command::{Cmd, CmdResult};
4use tuirealm::component::Component;
5use tuirealm::props::{
6 AttrValue, Attribute, Borders, Color, Layout, Props, QueryResult, Style, TextModifiers, Title,
7};
8use tuirealm::ratatui::Frame;
9use tuirealm::ratatui::layout::Rect;
10use tuirealm::state::State;
11
12use crate::prop_ext::CommonProps;
13
14#[must_use]
23pub struct Container {
24 common: CommonProps,
25 props: Props,
26 pub children: Vec<Box<dyn Component>>,
28}
29
30impl Default for Container {
31 fn default() -> Self {
32 Self {
33 common: CommonProps {
34 border: Some(Borders::default()),
35 ..CommonProps::default()
36 },
37 props: Props::default(),
38 children: Vec::new(),
39 }
40 }
41}
42
43impl Container {
44 pub fn foreground(mut self, fg: Color) -> Self {
46 self.attr(Attribute::Foreground, AttrValue::Color(fg));
47 self
48 }
49
50 pub fn background(mut self, bg: Color) -> Self {
52 self.attr(Attribute::Background, AttrValue::Color(bg));
53 self
54 }
55
56 pub fn modifiers(mut self, m: TextModifiers) -> Self {
58 self.attr(Attribute::TextProps, AttrValue::TextModifiers(m));
59 self
60 }
61
62 pub fn style(mut self, style: Style) -> Self {
66 self.attr(Attribute::Style, AttrValue::Style(style));
67 self
68 }
69
70 pub fn inactive(mut self, s: Style) -> Self {
72 self.attr(Attribute::UnfocusedBorderStyle, AttrValue::Style(s));
73 self
74 }
75
76 pub fn borders(mut self, b: Borders) -> Self {
78 self.attr(Attribute::Borders, AttrValue::Borders(b));
79 self
80 }
81
82 pub fn title<T: Into<Title>>(mut self, title: T) -> Self {
84 self.attr(Attribute::Title, AttrValue::Title(title.into()));
85 self
86 }
87
88 pub fn layout(mut self, layout: Layout) -> Self {
92 self.attr(Attribute::Layout, AttrValue::Layout(layout));
93 self
94 }
95
96 pub fn children(mut self, children: Vec<Box<dyn Component>>) -> Self {
98 self.children = children;
99 self
100 }
101}
102
103impl Component for Container {
104 fn view(&mut self, render: &mut Frame, mut area: Rect) {
105 if !self.common.display {
106 return;
107 }
108
109 if let Some(block) = self.common.get_block() {
110 let inner = block.inner(area);
111 render.render_widget(block, area);
113 area = inner;
114 }
115
116 if let Some(layout) = self
118 .props
119 .get(Attribute::Layout)
120 .and_then(AttrValue::as_layout)
121 {
122 let chunks = layout.chunks(area);
124 for (i, chunk) in chunks.into_iter().enumerate() {
126 if let Some(child) = self.children.get_mut(i) {
127 child.view(render, chunk);
128 }
129 }
130 }
131 }
132
133 fn query<'a>(&'a self, attr: Attribute) -> Option<QueryResult<'a>> {
134 if let Some(value) = self.common.get_for_query(attr) {
135 return Some(value);
136 }
137
138 self.props.get_for_query(attr)
139 }
140
141 fn attr(&mut self, attr: Attribute, value: AttrValue) {
142 if let Some(value) = self.common.set(attr, value.clone()) {
143 self.props.set(attr, value);
144 }
145
146 if matches!(attr, Attribute::Borders | Attribute::Title) {
148 return;
149 }
150
151 self.children
154 .iter_mut()
155 .for_each(|x| x.attr(attr, value.clone()));
156 }
157
158 fn state(&self) -> State {
159 State::None
160 }
161
162 fn perform(&mut self, cmd: Cmd) -> CmdResult {
163 CmdResult::Batch(self.children.iter_mut().map(|x| x.perform(cmd)).collect())
167 }
168}
169
170#[cfg(test)]
171mod tests {
172
173 use pretty_assertions::assert_eq;
174 use tuirealm::props::HorizontalAlignment;
175
176 use super::*;
177
178 #[test]
179 fn test_components_paragraph() {
180 let component = Container::default()
181 .background(Color::Blue)
182 .foreground(Color::Red)
183 .title(Title::from("title").alignment(HorizontalAlignment::Center));
184 assert_eq!(component.state(), State::None);
186 }
187}