1use crate::WindowControl;
5use rat_event::util::mouse_trap;
6use rat_event::{ConsumedEvent, HandleEvent, Outcome, ct_event};
7use ratatui::buffer::Buffer;
8use ratatui::layout::Rect;
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 trait Window<Context>: Any
20where
21 Context: 'static,
22{
23 fn set_top(&mut self, top: bool, ctx: &mut Context);
25 fn area(&self) -> Rect;
27}
28
29impl<Context> dyn Window<Context> {
30 pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
31 (self as &dyn Any).downcast_ref::<T>()
32 }
33
34 pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
35 (self as &mut dyn Any).downcast_mut::<T>()
36 }
37}
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
40pub enum WindowFrameOutcome {
41 Continue,
43 Unchanged,
45 Changed,
47 ShouldClose,
49 Moved,
51 Resized,
53}
54
55impl ConsumedEvent for WindowFrameOutcome {
56 fn is_consumed(&self) -> bool {
57 *self != WindowFrameOutcome::Continue
58 }
59}
60
61impl From<Outcome> for WindowFrameOutcome {
62 fn from(value: Outcome) -> Self {
63 match value {
64 Outcome::Continue => WindowFrameOutcome::Continue,
65 Outcome::Unchanged => WindowFrameOutcome::Unchanged,
66 Outcome::Changed => WindowFrameOutcome::Changed,
67 }
68 }
69}
70
71impl From<WindowFrameOutcome> for Outcome {
72 fn from(value: WindowFrameOutcome) -> Self {
73 match value {
74 WindowFrameOutcome::Continue => Outcome::Continue,
75 WindowFrameOutcome::Unchanged => Outcome::Unchanged,
76 WindowFrameOutcome::Changed => Outcome::Changed,
77 WindowFrameOutcome::Moved => Outcome::Changed,
78 WindowFrameOutcome::Resized => Outcome::Changed,
79 WindowFrameOutcome::ShouldClose => Outcome::Continue,
80 }
81 }
82}
83
84pub struct WindowList<Event, Context, Error> {
88 core: Rc<WindowListCore<Event, Context, Error>>,
89}
90
91struct WindowListCore<Event, Context, Error> {
92 len: Cell<usize>,
93 render: RefCell<
94 Vec<Box<dyn Fn(Rect, &mut Buffer, &mut dyn Window<Context>, &mut Context) + 'static>>,
95 >,
96 event: RefCell<
97 Vec<
98 Box<
99 dyn Fn(
100 &Event,
101 &mut dyn Window<Context>,
102 &mut Context,
103 ) -> Result<WindowControl<Event>, Error>
104 + 'static,
105 >,
106 >,
107 >,
108 type_id: RefCell<Vec<TypeId>>,
109 state: RefCell<Vec<Option<Box<dyn Window<Context>>>>>,
110}
111
112impl<Event, Context, Error> Clone for WindowList<Event, Context, Error> {
113 fn clone(&self) -> Self {
114 Self {
115 core: self.core.clone(),
116 }
117 }
118}
119
120impl<Event, Context, Error> Default for WindowList<Event, Context, Error> {
121 fn default() -> Self {
122 Self {
123 core: Rc::new(WindowListCore {
124 len: Cell::new(0),
125 render: Default::default(),
126 event: Default::default(),
127 type_id: Default::default(),
128 state: Default::default(),
129 }),
130 }
131 }
132}
133
134impl<Event, Context, Error> Debug for WindowList<Event, Context, Error> {
135 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
136 let state = self.core.state.borrow();
137 let is_proxy = state.iter().map(|v| v.is_none()).collect::<Vec<_>>();
138 let type_id = self.core.type_id.borrow();
139
140 f.debug_struct("DialogStackCore")
141 .field("len", &self.core.len.get())
142 .field("type_id", &type_id)
143 .field("is_proxy", &is_proxy)
144 .finish()
145 }
146}
147
148impl<Event, Context, Error> WindowList<Event, Context, Error> {
149 pub fn render(self, area: Rect, buf: &mut Buffer, ctx: &mut Context) {
151 for n in 0..self.core.len.get() {
152 let Some(mut state) = self.core.state.borrow_mut()[n].take() else {
153 panic!("state is gone");
154 };
155 let render_fn = mem::replace(
156 &mut self.core.render.borrow_mut()[n],
157 Box::new(|_, _, _, _| {}),
158 );
159
160 render_fn(area, buf, state.as_mut(), ctx);
161
162 self.core.render.borrow_mut()[n] = render_fn;
163 self.core.state.borrow_mut()[n] = Some(state);
164 }
165 }
166}
167
168impl<Event, Context, Error> WindowList<Event, Context, Error>
169where
170 Context: 'static,
171{
172 pub fn new() -> Self {
173 Self::default()
174 }
175
176 pub fn show(
180 &self,
181 render: impl Fn(Rect, &mut Buffer, &mut dyn Window<Context>, &'_ mut Context) + 'static,
182 event: impl Fn(
183 &Event,
184 &mut dyn Window<Context>,
185 &'_ mut Context,
186 ) -> Result<WindowControl<Event>, Error>
187 + 'static,
188 state: impl Window<Context>,
189 ctx: &mut Context,
190 ) {
191 self.core.len.update(|v| v + 1);
192 self.core.type_id.borrow_mut().push(state.type_id());
193 self.core.state.borrow_mut().push(Some(Box::new(state)));
194 self.core.event.borrow_mut().push(Box::new(event));
195 self.core.render.borrow_mut().push(Box::new(render));
196
197 self.set_top_window(ctx);
198 }
199
200 pub fn close(&self, n: usize, ctx: &mut Context) -> Box<dyn Window<Context>> {
210 for s in self.core.state.borrow().iter() {
211 if s.is_none() {
212 panic!("state is gone");
213 }
214 }
215
216 self.core.len.update(|v| v - 1);
217 self.core.type_id.borrow_mut().remove(n);
218 _ = self.core.event.borrow_mut().remove(n);
219 _ = self.core.render.borrow_mut().remove(n);
220
221 let r = self
222 .core
223 .state
224 .borrow_mut()
225 .remove(n)
226 .expect("state exists");
227
228 self.set_top_window(ctx);
229
230 r
231 }
232
233 pub fn to_front(&self, n: usize, ctx: &mut Context) {
243 for s in self.core.state.borrow().iter() {
244 if s.is_none() {
245 panic!("state is gone");
246 }
247 }
248
249 let type_id = self.core.type_id.borrow_mut().remove(n);
250 let state = self.core.state.borrow_mut().remove(n);
251 let event = self.core.event.borrow_mut().remove(n);
252 let render = self.core.render.borrow_mut().remove(n);
253
254 self.core.type_id.borrow_mut().push(type_id);
255 self.core.state.borrow_mut().push(state);
256 self.core.event.borrow_mut().push(event);
257 self.core.render.borrow_mut().push(render);
258
259 self.set_top_window(ctx);
260 }
261
262 pub fn to_back(&self, n: usize, ctx: &mut Context) {
271 for s in self.core.state.borrow().iter() {
272 if s.is_none() {
273 panic!("state is gone");
274 }
275 }
276
277 let type_id = self.core.type_id.borrow_mut().remove(n);
278 let state = self.core.state.borrow_mut().remove(n);
279 let event = self.core.event.borrow_mut().remove(n);
280 let render = self.core.render.borrow_mut().remove(n);
281
282 self.core.type_id.borrow_mut().insert(0, type_id);
283 self.core.state.borrow_mut().insert(0, state);
284 self.core.event.borrow_mut().insert(0, event);
285 self.core.render.borrow_mut().insert(0, render);
286
287 self.set_top_window(ctx);
288 }
289
290 fn set_top_window(&self, ctx: &mut Context) {
291 let len = self.len();
292
293 if len > 0 {
294 let mut states = self.core.state.borrow_mut();
295 for i in 0..len - 1 {
296 if let Some(s) = &mut states[i] {
297 s.set_top(false, ctx);
298 } else {
299 panic!("state is gone");
300 }
301 }
302 if let Some(s) = &mut states[len - 1] {
303 s.set_top(true, ctx);
304 } else {
305 panic!("state is gone");
306 }
307 }
308 }
309
310 pub fn is_empty(&self) -> bool {
312 self.core.type_id.borrow().is_empty()
313 }
314
315 pub fn len(&self) -> usize {
317 self.core.len.get()
318 }
319
320 pub fn state_is<S: 'static>(&self, n: usize) -> bool {
322 self.core.type_id.borrow()[n] == TypeId::of::<S>()
323 }
324
325 #[allow(clippy::manual_find)]
327 pub fn top<S: 'static>(&self) -> Option<usize> {
328 for n in (0..self.core.len.get()).rev() {
329 if self.core.type_id.borrow()[n] == TypeId::of::<S>() {
330 return Some(n);
331 }
332 }
333 None
334 }
335
336 pub fn find<S: 'static>(&self) -> Vec<usize> {
338 self.core
339 .type_id
340 .borrow()
341 .iter()
342 .enumerate()
343 .rev()
344 .filter_map(|(n, v)| {
345 if *v == TypeId::of::<S>() {
346 Some(n)
347 } else {
348 None
349 }
350 })
351 .collect()
352 }
353
354 pub fn get_mut<'a, S: 'static>(&'a self, n: usize) -> Option<RefMut<'a, S>> {
366 let state = self.core.state.borrow_mut();
367
368 RefMut::filter_map(state, |v| {
369 let state = &mut v[n];
370 if let Some(state) = state.as_mut() {
371 if let Some(state) = (state.as_mut() as &mut dyn Any).downcast_mut::<S>() {
372 Some(state)
373 } else {
374 None
375 }
376 } else {
377 None
378 }
379 })
380 .ok()
381 }
382
383 pub fn get<'a, S: 'static>(&'a self, n: usize) -> Option<Ref<'a, S>> {
395 let state = self.core.state.borrow();
396
397 Ref::filter_map(state, |v| {
398 let state = &v[n];
399 if let Some(state) = state.as_ref() {
400 if let Some(state) = (state.as_ref() as &dyn Any).downcast_ref::<S>() {
401 Some(state)
402 } else {
403 None
404 }
405 } else {
406 None
407 }
408 })
409 .ok()
410 }
411}
412
413impl<Event, Context, Error> HandleEvent<Event, &mut Context, Result<WindowControl<Event>, Error>>
419 for WindowList<Event, Context, Error>
420where
421 Event: TryAsRef<crossterm::event::Event>,
422 Error: 'static,
423 Event: 'static,
424 Context: 'static,
425{
426 fn handle(&mut self, event: &Event, ctx: &mut Context) -> Result<WindowControl<Event>, Error> {
427 let mut r_front = WindowControl::Continue;
428
429 for n in (0..self.core.len.get()).rev() {
430 let (to_front, area) = {
431 let state = self.core.state.borrow();
432 let state = state[n].as_ref().expect("state is gone");
433 match event.try_as_ref() {
434 Some(ct_event!(mouse down Left for x,y))
435 if state.area().contains((*x, *y).into()) =>
436 {
437 (true, state.area())
438 }
439 _ => (false, state.area()),
440 }
441 };
442
443 let Some(mut state) = self.core.state.borrow_mut()[n].take() else {
444 panic!("state is gone");
445 };
446 let event_fn = mem::replace(
447 &mut self.core.event.borrow_mut()[n],
448 Box::new(|_, _, _| Ok(WindowControl::Continue)),
449 );
450
451 let r = event_fn(event, state.as_mut(), ctx);
452
453 self.core.event.borrow_mut()[n] = event_fn;
454 self.core.state.borrow_mut()[n] = Some(state);
455
456 if to_front {
457 self.to_front(n, ctx);
458 r_front = WindowControl::Changed;
459 };
460
461 match r {
462 Ok(r) => match r {
463 WindowControl::Close(_) => {
464 self.close(n, ctx);
465 return Ok(max(r, r_front));
466 }
467 WindowControl::Event(_) => {
468 return Ok(max(r, r_front));
469 }
470 WindowControl::Unchanged => {
471 return Ok(max(r, r_front));
472 }
473 WindowControl::Changed => {
474 return Ok(max(r, r_front));
475 }
476 WindowControl::Continue => {
477 if let Some(event) = event.try_as_ref() {
478 if mouse_trap(event, area).is_consumed() {
479 return Ok(max(WindowControl::Unchanged, r_front));
480 }
481 }
482 }
483 },
484 Err(e) => return Err(e),
485 }
486 }
487
488 Ok(r_front)
489 }
490}
491
492fn max<Event>(
493 primary: WindowControl<Event>,
494 secondary: WindowControl<Event>,
495) -> WindowControl<Event> {
496 let s = match &primary {
497 WindowControl::Continue => 0,
498 WindowControl::Unchanged => 1,
499 WindowControl::Changed => 2,
500 WindowControl::Event(_) => 3,
501 WindowControl::Close(_) => 4,
502 };
503 let t = match &secondary {
504 WindowControl::Continue => 0,
505 WindowControl::Unchanged => 1,
506 WindowControl::Changed => 2,
507 WindowControl::Event(_) => 3,
508 WindowControl::Close(_) => 4,
509 };
510 if s > t { primary } else { secondary }
511}
512
513pub fn handle_window_list<Event, Context, Error>(
519 mut window_list: WindowList<Event, Context, Error>,
520 event: &Event,
521 ctx: &mut Context,
522) -> Result<WindowControl<Event>, Error>
523where
524 Event: TryAsRef<crossterm::event::Event>,
525 Error: 'static,
526 Event: 'static,
527 Error: Debug,
528 Event: Debug,
529 Context: 'static,
530{
531 window_list.handle(event, ctx)
532}