1use crate::WindowControl;
3use rat_event::HandleEvent;
4use ratatui::buffer::Buffer;
5use ratatui::layout::Rect;
6use std::any::{Any, TypeId};
7use std::cell::{Cell, Ref, RefCell, RefMut};
8use std::fmt::{Debug, Formatter};
9use std::mem;
10use std::rc::Rc;
11use try_as::traits::TryAsRef;
12
13pub struct DialogStack<Event, Context, Error> {
25 core: Rc<DialogStackCore<Event, Context, Error>>,
26}
27
28struct DialogStackCore<Event, Context, Error> {
29 len: Cell<usize>,
30 render: RefCell<Vec<Box<dyn Fn(Rect, &mut Buffer, &mut dyn Any, &mut Context) + 'static>>>,
31 event: RefCell<
32 Vec<
33 Box<
34 dyn Fn(&Event, &mut dyn Any, &mut Context) -> Result<WindowControl<Event>, Error>
35 + 'static,
36 >,
37 >,
38 >,
39 type_id: RefCell<Vec<TypeId>>,
40 state: RefCell<Vec<Option<Box<dyn Any>>>>,
41}
42
43impl<Event, Context, Error> Clone for DialogStack<Event, Context, Error> {
44 fn clone(&self) -> Self {
45 Self {
46 core: self.core.clone(),
47 }
48 }
49}
50
51impl<Event, Context, Error> Default for DialogStack<Event, Context, Error> {
52 fn default() -> Self {
53 Self {
54 core: Rc::new(DialogStackCore {
55 len: Cell::new(0),
56 render: Default::default(),
57 event: Default::default(),
58 type_id: Default::default(),
59 state: Default::default(),
60 }),
61 }
62 }
63}
64
65impl<Event, Context, Error> Debug for DialogStack<Event, Context, Error> {
66 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
67 let state = self.core.state.borrow();
68 let is_proxy = state.iter().map(|v| v.is_none()).collect::<Vec<_>>();
69 let type_id = self.core.type_id.borrow();
70
71 f.debug_struct("DialogStackCore")
72 .field("len", &self.core.len.get())
73 .field("type_id", &type_id)
74 .field("is_proxy", &is_proxy)
75 .finish()
76 }
77}
78
79impl<Event, Context, Error> DialogStack<Event, Context, Error> {
80 pub fn render(self, area: Rect, buf: &mut Buffer, ctx: &mut Context) {
82 for n in 0..self.core.len.get() {
83 let Some(mut state) = self.core.state.borrow_mut()[n].take() else {
84 panic!("state is gone");
85 };
86 let render_fn = mem::replace(
87 &mut self.core.render.borrow_mut()[n],
88 Box::new(|_, _, _, _| {}),
89 );
90
91 render_fn(area, buf, state.as_mut(), ctx);
92
93 self.core.render.borrow_mut()[n] = render_fn;
94 self.core.state.borrow_mut()[n] = Some(state);
95 }
96 }
97}
98
99impl<Event, Context, Error> DialogStack<Event, Context, Error> {
100 pub fn new() -> Self {
101 Self::default()
102 }
103
104 pub fn push(
111 &self,
112 render: impl Fn(Rect, &mut Buffer, &mut dyn Any, &'_ mut Context) + 'static,
113 event: impl Fn(&Event, &mut dyn Any, &'_ mut Context) -> Result<WindowControl<Event>, Error>
114 + 'static,
115 state: impl Any,
116 ) {
117 self.core.len.update(|v| v + 1);
118 self.core.type_id.borrow_mut().push(state.type_id());
119 self.core.state.borrow_mut().push(Some(Box::new(state)));
120 self.core.event.borrow_mut().push(Box::new(event));
121 self.core.render.borrow_mut().push(Box::new(render));
122 }
123
124 pub fn pop(&self) -> Option<Box<dyn Any>> {
134 self.core.len.update(|v| v - 1);
135 self.core.type_id.borrow_mut().pop();
136 self.core.event.borrow_mut().pop();
137 self.core.render.borrow_mut().pop();
138 let Some(s) = self.core.state.borrow_mut().pop() else {
139 return None;
140 };
141 if s.is_none() {
142 panic!("state is gone");
143 }
144 s
145 }
146
147 pub fn remove(&self, n: usize) -> Box<dyn Any> {
157 for s in self.core.state.borrow().iter() {
158 if s.is_none() {
159 panic!("state is gone");
160 }
161 }
162
163 self.core.len.update(|v| v - 1);
164 self.core.type_id.borrow_mut().remove(n);
165 _ = self.core.event.borrow_mut().remove(n);
166 _ = self.core.render.borrow_mut().remove(n);
167
168 self.core
169 .state
170 .borrow_mut()
171 .remove(n)
172 .expect("state exists")
173 }
174
175 pub fn is_empty(&self) -> bool {
177 self.core.type_id.borrow().is_empty()
178 }
179
180 pub fn len(&self) -> usize {
182 self.core.len.get()
183 }
184
185 pub fn state_is<S: 'static>(&self, n: usize) -> bool {
187 self.core.type_id.borrow()[n] == TypeId::of::<S>()
188 }
189
190 #[allow(clippy::manual_find)]
192 pub fn top<S: 'static>(&self) -> Option<usize> {
193 for n in (0..self.core.len.get()).rev() {
194 if self.core.type_id.borrow()[n] == TypeId::of::<S>() {
195 return Some(n);
196 }
197 }
198 None
199 }
200
201 pub fn find<S: 'static>(&self) -> Vec<usize> {
203 self.core
204 .type_id
205 .borrow()
206 .iter()
207 .enumerate()
208 .rev()
209 .filter_map(|(n, v)| {
210 if *v == TypeId::of::<S>() {
211 Some(n)
212 } else {
213 None
214 }
215 })
216 .collect()
217 }
218
219 pub fn get<'a, S: 'static>(&'a self, n: usize) -> Ref<'a, S> {
228 self.try_get(n).expect("recursion or wrong type")
229 }
230
231 pub fn get_mut<'a, S: 'static>(&'a self, n: usize) -> RefMut<'a, S> {
240 self.try_get_mut(n).expect("recursion or wrong type")
241 }
242
243 pub fn try_get_mut<'a, S: 'static>(&'a self, n: usize) -> Option<RefMut<'a, S>> {
255 let state = self.core.state.borrow_mut();
256
257 RefMut::filter_map(state, |v| {
258 let state = &mut v[n];
259 if let Some(state) = state.as_mut() {
260 if let Some(state) = state.downcast_mut::<S>() {
261 Some(state)
262 } else {
263 None
264 }
265 } else {
266 None
267 }
268 })
269 .ok()
270 }
271
272 pub fn try_get<'a, S: 'static>(&'a self, n: usize) -> Option<Ref<'a, S>> {
284 let state = self.core.state.borrow();
285
286 Ref::filter_map(state, |v| {
287 let state = &v[n];
288 if let Some(state) = state.as_ref() {
289 if let Some(state) = state.downcast_ref::<S>() {
290 Some(state)
291 } else {
292 None
293 }
294 } else {
295 None
296 }
297 })
298 .ok()
299 }
300}
301
302impl<Event, Context, Error> HandleEvent<Event, &mut Context, Result<WindowControl<Event>, Error>>
308 for DialogStack<Event, Context, Error>
309where
310 Event: TryAsRef<crossterm::event::Event>,
311 Error: 'static,
312 Event: 'static,
313{
314 fn handle(&mut self, event: &Event, ctx: &mut Context) -> Result<WindowControl<Event>, Error> {
315 for n in (0..self.core.len.get()).rev() {
316 let Some(mut state) = self.core.state.borrow_mut()[n].take() else {
317 panic!("state is gone");
318 };
319 let event_fn = mem::replace(
320 &mut self.core.event.borrow_mut()[n],
321 Box::new(|_, _, _| Ok(WindowControl::Continue)),
322 );
323
324 let r = event_fn(event, state.as_mut(), ctx);
325
326 self.core.event.borrow_mut()[n] = event_fn;
327 self.core.state.borrow_mut()[n] = Some(state);
328
329 match r {
330 Ok(r) => match r {
331 WindowControl::Close(_) => {
332 self.remove(n);
333 return Ok(r);
334 }
335 WindowControl::Event(_) => {
336 return Ok(r);
337 }
338 WindowControl::Unchanged => {
339 return Ok(r);
340 }
341 WindowControl::Changed => {
342 return Ok(r);
343 }
344 WindowControl::Continue => {
345 }
347 },
348 Err(e) => return Err(e),
349 }
350 }
351
352 if self.len() > 0 {
353 let event: Option<&crossterm::event::Event> = event.try_as_ref();
355 if event.is_some() {
356 Ok(WindowControl::Unchanged)
357 } else {
358 Ok(WindowControl::Continue)
359 }
360 } else {
361 Ok(WindowControl::Continue)
362 }
363 }
364}
365
366pub fn handle_dialog_stack<Event, Context, Error>(
372 mut dialog_stack: DialogStack<Event, Context, Error>,
373 event: &Event,
374 ctx: &mut Context,
375) -> Result<WindowControl<Event>, Error>
376where
377 Event: TryAsRef<crossterm::event::Event>,
378 Error: 'static,
379 Event: 'static,
380{
381 dialog_stack.handle(event, ctx)
382}