1use crate::WindowControl;
5use rat_event::HandleEvent;
6use ratatui::buffer::Buffer;
7use ratatui::layout::Rect;
8use ratatui::widgets::StatefulWidget;
9use std::any::{Any, TypeId};
10use std::cell::{Cell, Ref, RefCell, RefMut};
11use std::fmt::{Debug, Formatter};
12use std::mem;
13use std::rc::Rc;
14use try_as::traits::TryAsRef;
15
16pub struct DialogStack<Event, Context, Error> {
29 core: Rc<DialogStackCore<Event, Context, Error>>,
30}
31
32struct DialogStackCore<Event, Context, Error> {
33 len: Cell<usize>,
34 render: RefCell<Vec<Box<dyn Fn(Rect, &mut Buffer, &mut dyn Any, &mut Context) + 'static>>>,
35 event: RefCell<
36 Vec<
37 Box<
38 dyn Fn(&Event, &mut dyn Any, &mut Context) -> Result<WindowControl<Event>, Error>
39 + 'static,
40 >,
41 >,
42 >,
43 type_id: RefCell<Vec<TypeId>>,
44 state: RefCell<Vec<Option<Box<dyn Any>>>>,
45}
46
47impl<Event, Context, Error> Clone for DialogStack<Event, Context, Error> {
48 fn clone(&self) -> Self {
49 Self {
50 core: self.core.clone(),
51 }
52 }
53}
54
55impl<Event, Context, Error> Default for DialogStack<Event, Context, Error> {
56 fn default() -> Self {
57 Self {
58 core: Rc::new(DialogStackCore {
59 len: Cell::new(0),
60 render: Default::default(),
61 event: Default::default(),
62 type_id: Default::default(),
63 state: Default::default(),
64 }),
65 }
66 }
67}
68
69impl<Event, Context, Error> Debug for DialogStack<Event, Context, Error> {
70 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
71 let state = self.core.state.borrow();
72 let is_proxy = state.iter().map(|v| v.is_none()).collect::<Vec<_>>();
73 let type_id = self.core.type_id.borrow();
74
75 f.debug_struct("DialogStackCore")
76 .field("len", &self.core.len.get())
77 .field("type_id", &type_id)
78 .field("is_proxy", &is_proxy)
79 .finish()
80 }
81}
82
83impl<Event, Context, Error> StatefulWidget for DialogStack<Event, Context, Error> {
84 type State = Context;
85
86 fn render(self, area: Rect, buf: &mut Buffer, ctx: &mut Self::State) {
87 for n in 0..self.core.len.get() {
88 let Some(mut state) = self.core.state.borrow_mut()[n].take() else {
89 panic!("state is gone");
90 };
91 let render_fn = mem::replace(
92 &mut self.core.render.borrow_mut()[n],
93 Box::new(|_, _, _, _| {}),
94 );
95
96 render_fn(area, buf, state.as_mut(), ctx);
97
98 self.core.render.borrow_mut()[n] = render_fn;
99 self.core.state.borrow_mut()[n] = Some(state);
100 }
101 }
102}
103
104impl<Event, Context, Error> DialogStack<Event, Context, Error> {
105 pub fn new() -> Self {
106 Self::default()
107 }
108
109 pub fn push(
116 &self,
117 render: impl Fn(Rect, &mut Buffer, &mut dyn Any, &'_ mut Context) + 'static,
118 event: impl Fn(&Event, &mut dyn Any, &'_ mut Context) -> Result<WindowControl<Event>, Error>
119 + 'static,
120 state: impl Any,
121 ) {
122 self.core.len.update(|v| v + 1);
123 self.core.type_id.borrow_mut().push(state.type_id());
124 self.core.state.borrow_mut().push(Some(Box::new(state)));
125 self.core.event.borrow_mut().push(Box::new(event));
126 self.core.render.borrow_mut().push(Box::new(render));
127 }
128
129 pub fn pop(&self) -> Option<Box<dyn Any>> {
139 self.core.len.update(|v| v - 1);
140 self.core.type_id.borrow_mut().pop();
141 self.core.event.borrow_mut().pop();
142 self.core.render.borrow_mut().pop();
143 let Some(s) = self.core.state.borrow_mut().pop() else {
144 return None;
145 };
146 if s.is_none() {
147 panic!("state is gone");
148 }
149 s
150 }
151
152 pub fn remove(&self, n: usize) -> Box<dyn Any> {
162 for s in self.core.state.borrow().iter() {
163 if s.is_none() {
164 panic!("state is gone");
165 }
166 }
167
168 self.core.len.update(|v| v - 1);
169 self.core.type_id.borrow_mut().remove(n);
170 _ = self.core.event.borrow_mut().remove(n);
171 _ = self.core.render.borrow_mut().remove(n);
172
173 self.core
174 .state
175 .borrow_mut()
176 .remove(n)
177 .expect("state exists")
178 }
179
180 pub fn is_empty(&self) -> bool {
182 self.core.type_id.borrow().is_empty()
183 }
184
185 pub fn len(&self) -> usize {
187 self.core.len.get()
188 }
189
190 pub fn state_is<S: 'static>(&self, n: usize) -> bool {
192 self.core.type_id.borrow()[n] == TypeId::of::<S>()
193 }
194
195 #[allow(clippy::manual_find)]
197 pub fn top<S: 'static>(&self) -> Option<usize> {
198 for n in (0..self.core.len.get()).rev() {
199 if self.core.type_id.borrow()[n] == TypeId::of::<S>() {
200 return Some(n);
201 }
202 }
203 None
204 }
205
206 pub fn find<S: 'static>(&self) -> Vec<usize> {
208 self.core
209 .type_id
210 .borrow()
211 .iter()
212 .enumerate()
213 .rev()
214 .filter_map(|(n, v)| {
215 if *v == TypeId::of::<S>() {
216 Some(n)
217 } else {
218 None
219 }
220 })
221 .collect()
222 }
223
224 pub fn get_mut<'a, S: 'static>(&'a self, n: usize) -> Option<RefMut<'a, S>> {
236 let state = self.core.state.borrow_mut();
237
238 RefMut::filter_map(state, |v| {
239 let state = &mut v[n];
240 if let Some(state) = state.as_mut() {
241 if let Some(state) = state.downcast_mut::<S>() {
242 Some(state)
243 } else {
244 None
245 }
246 } else {
247 None
248 }
249 })
250 .ok()
251 }
252
253 pub fn get<'a, S: 'static>(&'a self, n: usize) -> Option<Ref<'a, S>> {
265 let state = self.core.state.borrow();
266
267 Ref::filter_map(state, |v| {
268 let state = &v[n];
269 if let Some(state) = state.as_ref() {
270 if let Some(state) = state.downcast_ref::<S>() {
271 Some(state)
272 } else {
273 None
274 }
275 } else {
276 None
277 }
278 })
279 .ok()
280 }
281}
282
283impl<Event, Context, Error> HandleEvent<Event, &mut Context, Result<WindowControl<Event>, Error>>
293 for DialogStack<Event, Context, Error>
294where
295 Event: TryAsRef<crossterm::event::Event>,
296 Error: 'static,
297 Event: 'static,
298{
299 fn handle(&mut self, event: &Event, ctx: &mut Context) -> Result<WindowControl<Event>, Error> {
300 for n in (0..self.core.len.get()).rev() {
301 let Some(mut state) = self.core.state.borrow_mut()[n].take() else {
302 panic!("state is gone");
303 };
304 let event_fn = mem::replace(
305 &mut self.core.event.borrow_mut()[n],
306 Box::new(|_, _, _| Ok(WindowControl::Continue)),
307 );
308
309 let r = event_fn(event, state.as_mut(), ctx);
310
311 self.core.event.borrow_mut()[n] = event_fn;
312 self.core.state.borrow_mut()[n] = Some(state);
313
314 match r {
315 Ok(r) => match r {
316 WindowControl::Close(_) => {
317 self.remove(n);
318 return Ok(r);
319 }
320 WindowControl::Event(_) => {
321 return Ok(r);
322 }
323 WindowControl::Unchanged => {
324 return Ok(r);
325 }
326 WindowControl::Changed => {
327 return Ok(r);
328 }
329 WindowControl::Continue => {
330 }
332 },
333 Err(e) => return Err(e),
334 }
335
336 let event: Option<&crossterm::event::Event> = event.try_as_ref();
338 if event.is_some() {
339 return Ok(WindowControl::Unchanged);
340 }
341 }
342
343 Ok(WindowControl::Continue)
344 }
345}
346
347pub fn handle_dialog_stack<Event, Context, Error>(
353 mut dialog_stack: DialogStack<Event, Context, Error>,
354 event: &Event,
355 ctx: &mut Context,
356) -> Result<WindowControl<Event>, Error>
357where
358 Event: TryAsRef<crossterm::event::Event>,
359 Error: 'static,
360 Event: 'static,
361{
362 dialog_stack.handle(event, ctx)
363}