1use crate::tui::Component;
2use crate::tui::component::RenderCache;
3
4struct ChildCache {
6 cache: Option<RenderCache>,
8 dirty: bool,
10}
11
12impl ChildCache {
13 fn new() -> Self {
14 Self {
15 cache: None,
16 dirty: true,
17 }
18 }
19}
20
21pub struct Container {
24 children: Vec<Box<dyn Component>>,
25 child_caches: Vec<ChildCache>,
27}
28
29impl Container {
30 pub fn new() -> Self {
31 Self {
32 children: Vec::new(),
33 child_caches: Vec::new(),
34 }
35 }
36
37 pub fn add_child(&mut self, component: Box<dyn Component>) {
38 self.child_caches.push(ChildCache::new());
39 self.children.push(component);
40 }
41
42 pub fn remove_child(&mut self, component: &dyn Component) {
43 let idx = self.children.iter().position(|c| {
45 std::ptr::eq(
46 c.as_ref() as *const dyn Component,
47 component as *const dyn Component,
48 )
49 });
50 if let Some(idx) = idx {
51 self.children.remove(idx);
52 self.child_caches.remove(idx);
53 }
54 }
55
56 pub fn clear(&mut self) {
57 self.children.clear();
58 self.child_caches.clear();
59 }
60
61 pub fn children(&self) -> &[Box<dyn Component>] {
62 &self.children
63 }
64
65 pub fn children_mut(&mut self) -> &mut [Box<dyn Component>] {
66 &mut self.children
67 }
68
69 pub fn invalidate_all(&mut self) {
71 for cache in &mut self.child_caches {
72 cache.dirty = true;
73 cache.cache = None;
74 }
75 }
76
77 pub fn invalidate_child(&mut self, index: usize) {
79 if let Some(cache) = self.child_caches.get_mut(index) {
80 cache.dirty = true;
81 cache.cache = None;
82 }
83 }
84
85 pub fn len(&self) -> usize {
87 self.children.len()
88 }
89
90 pub fn is_empty(&self) -> bool {
92 self.children.is_empty()
93 }
94}
95
96impl Default for Container {
97 fn default() -> Self {
98 Self::new()
99 }
100}
101
102impl Component for Container {
103 fn render(&self, width: usize) -> Vec<String> {
104 let mut lines = Vec::new();
108 for child in &self.children {
109 let child_lines = child.render(width);
110 lines.extend(child_lines);
111 }
112 lines
113 }
114
115 fn handle_input(&mut self, key: &crossterm::event::KeyEvent) -> bool {
116 for child in self.children.iter_mut().rev() {
117 if child.handle_input(key) {
118 return true;
119 }
120 }
121 false
122 }
123
124 fn invalidate(&mut self) {
125 for child in &mut self.children {
126 child.invalidate();
127 }
128 for cache in &mut self.child_caches {
130 cache.dirty = true;
131 cache.cache = None;
132 }
133 }
134
135 fn is_dirty(&self) -> bool {
136 self.child_caches.iter().any(|c| c.dirty)
138 }
139
140 fn clear_dirty(&mut self) {
141 for cache in &mut self.child_caches {
142 cache.dirty = false;
143 }
144 }
145}
146
147pub struct CachedContainer {
150 inner: Container,
151 cache: Option<RenderCache>,
152 dirty: bool,
153}
154
155impl CachedContainer {
156 pub fn new() -> Self {
157 Self {
158 inner: Container::new(),
159 cache: None,
160 dirty: true,
161 }
162 }
163
164 pub fn inner(&self) -> &Container {
165 &self.inner
166 }
167
168 pub fn inner_mut(&mut self) -> &mut Container {
169 self.dirty = true;
170 &mut self.inner
171 }
172
173 pub fn add_child(&mut self, component: Box<dyn Component>) {
175 self.inner.add_child(component);
176 self.dirty = true;
177 }
178
179 pub fn remove_child(&mut self, component: &dyn Component) {
181 self.inner.remove_child(component);
182 self.dirty = true;
183 }
184
185 pub fn clear(&mut self) {
187 self.inner.clear();
188 self.cache = None;
189 self.dirty = true;
190 }
191
192 pub fn invalidate(&mut self) {
194 self.dirty = true;
195 self.cache = None;
196 self.inner.invalidate_all();
197 }
198
199 pub fn children(&self) -> &[Box<dyn Component>] {
201 self.inner.children()
202 }
203
204 pub fn children_mut(&mut self) -> &mut [Box<dyn Component>] {
206 self.dirty = true;
207 self.inner.children_mut()
208 }
209
210 pub fn len(&self) -> usize {
212 self.inner.len()
213 }
214
215 pub fn is_empty(&self) -> bool {
217 self.inner.is_empty()
218 }
219}
220
221impl Default for CachedContainer {
222 fn default() -> Self {
223 Self::new()
224 }
225}
226
227impl Component for CachedContainer {
228 fn render(&self, width: usize) -> Vec<String> {
229 self.inner.render(width)
233 }
234
235 fn handle_input(&mut self, key: &crossterm::event::KeyEvent) -> bool {
236 let result = self.inner.handle_input(key);
237 if result {
238 self.dirty = true;
239 }
240 result
241 }
242
243 fn invalidate(&mut self) {
244 self.dirty = true;
245 self.cache = None;
246 self.inner.invalidate();
247 }
248
249 fn is_dirty(&self) -> bool {
250 self.dirty || self.inner.is_dirty()
251 }
252
253 fn clear_dirty(&mut self) {
254 self.dirty = false;
255 self.inner.clear_dirty();
256 }
257}