1use crate::WindowControl;
3use rat_event::util::mouse_trap;
4use rat_event::{ConsumedEvent, HandleEvent, Outcome, ct_event};
5use ratatui::buffer::Buffer;
6use ratatui::layout::Rect;
7use std::any::{Any, TypeId};
8use std::cell::{Cell, Ref, RefCell, RefMut};
9use std::fmt::{Debug, Formatter};
10use std::mem;
11use std::rc::Rc;
12use try_as::traits::TryAsRef;
13
14pub mod mac_frame;
15pub mod window_frame;
16
17pub trait Window: Any {
18 fn set_top(&mut self, top: bool);
20 fn area(&self) -> Rect;
22}
23
24impl dyn Window {
25 pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
26 (self as &dyn Any).downcast_ref::<T>()
27 }
28
29 pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
30 (self as &mut dyn Any).downcast_mut::<T>()
31 }
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
35pub enum WindowFrameOutcome {
36 Continue,
38 Unchanged,
40 Changed,
42 ShouldClose,
44 Moved,
46 Resized,
48}
49
50impl ConsumedEvent for WindowFrameOutcome {
51 fn is_consumed(&self) -> bool {
52 *self != WindowFrameOutcome::Continue
53 }
54}
55
56impl From<Outcome> for WindowFrameOutcome {
57 fn from(value: Outcome) -> Self {
58 match value {
59 Outcome::Continue => WindowFrameOutcome::Continue,
60 Outcome::Unchanged => WindowFrameOutcome::Unchanged,
61 Outcome::Changed => WindowFrameOutcome::Changed,
62 }
63 }
64}
65
66impl From<WindowFrameOutcome> for Outcome {
67 fn from(value: WindowFrameOutcome) -> Self {
68 match value {
69 WindowFrameOutcome::Continue => Outcome::Continue,
70 WindowFrameOutcome::Unchanged => Outcome::Unchanged,
71 WindowFrameOutcome::Changed => Outcome::Changed,
72 WindowFrameOutcome::Moved => Outcome::Changed,
73 WindowFrameOutcome::Resized => Outcome::Changed,
74 WindowFrameOutcome::ShouldClose => Outcome::Continue,
75 }
76 }
77}
78
79pub struct WindowList<Event, Context, Error> {
83 core: Rc<WindowListCore<Event, Context, Error>>,
84}
85
86struct WindowListCore<Event, Context, Error> {
87 len: Cell<usize>,
88 render: RefCell<Vec<Box<dyn Fn(Rect, &mut Buffer, &mut dyn Window, &mut Context) + 'static>>>,
89 event: RefCell<
90 Vec<
91 Box<
92 dyn Fn(&Event, &mut dyn Window, &mut Context) -> Result<WindowControl<Event>, Error>
93 + 'static,
94 >,
95 >,
96 >,
97 type_id: RefCell<Vec<TypeId>>,
98 state: RefCell<Vec<Option<Box<dyn Window>>>>,
99}
100
101impl<Event, Context, Error> Clone for WindowList<Event, Context, Error> {
102 fn clone(&self) -> Self {
103 Self {
104 core: self.core.clone(),
105 }
106 }
107}
108
109impl<Event, Context, Error> Default for WindowList<Event, Context, Error> {
110 fn default() -> Self {
111 Self {
112 core: Rc::new(WindowListCore {
113 len: Cell::new(0),
114 render: Default::default(),
115 event: Default::default(),
116 type_id: Default::default(),
117 state: Default::default(),
118 }),
119 }
120 }
121}
122
123impl<Event, Context, Error> Debug for WindowList<Event, Context, Error> {
124 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
125 let state = self.core.state.borrow();
126 let is_proxy = state.iter().map(|v| v.is_none()).collect::<Vec<_>>();
127 let type_id = self.core.type_id.borrow();
128
129 f.debug_struct("DialogStackCore")
130 .field("len", &self.core.len.get())
131 .field("type_id", &type_id)
132 .field("is_proxy", &is_proxy)
133 .finish()
134 }
135}
136
137impl<Event, Context, Error> WindowList<Event, Context, Error> {
138 pub fn render(self, area: Rect, buf: &mut Buffer, ctx: &mut Context) {
140 for n in 0..self.core.len.get() {
141 let Some(mut state) = self.core.state.borrow_mut()[n].take() else {
142 panic!("state is gone");
143 };
144 let render_fn = mem::replace(
145 &mut self.core.render.borrow_mut()[n],
146 Box::new(|_, _, _, _| {}),
147 );
148
149 render_fn(area, buf, state.as_mut(), ctx);
150
151 self.core.render.borrow_mut()[n] = render_fn;
152 self.core.state.borrow_mut()[n] = Some(state);
153 }
154 }
155}
156
157impl<Event, Context, Error> WindowList<Event, Context, Error> {
158 pub fn new() -> Self {
159 Self::default()
160 }
161
162 pub fn show(
166 &self,
167 render: impl Fn(Rect, &mut Buffer, &mut dyn Window, &'_ mut Context) + 'static,
168 event: impl Fn(&Event, &mut dyn Window, &'_ mut Context) -> Result<WindowControl<Event>, Error>
169 + 'static,
170 state: impl Window,
171 ) {
172 self.core.len.update(|v| v + 1);
173 self.core.type_id.borrow_mut().push(state.type_id());
174 self.core.state.borrow_mut().push(Some(Box::new(state)));
175 self.core.event.borrow_mut().push(Box::new(event));
176 self.core.render.borrow_mut().push(Box::new(render));
177
178 self.set_top_window();
179 }
180
181 pub fn close(&self, n: usize) -> Box<dyn Window> {
191 for s in self.core.state.borrow().iter() {
192 if s.is_none() {
193 panic!("state is gone");
194 }
195 }
196
197 self.core.len.update(|v| v - 1);
198 self.core.type_id.borrow_mut().remove(n);
199 _ = self.core.event.borrow_mut().remove(n);
200 _ = self.core.render.borrow_mut().remove(n);
201
202 let r = self
203 .core
204 .state
205 .borrow_mut()
206 .remove(n)
207 .expect("state exists");
208
209 self.set_top_window();
210
211 r
212 }
213
214 pub fn to_front(&self, n: usize) {
224 for s in self.core.state.borrow().iter() {
225 if s.is_none() {
226 panic!("state is gone");
227 }
228 }
229
230 let type_id = self.core.type_id.borrow_mut().remove(n);
231 let state = self.core.state.borrow_mut().remove(n);
232 let event = self.core.event.borrow_mut().remove(n);
233 let render = self.core.render.borrow_mut().remove(n);
234
235 self.core.type_id.borrow_mut().push(type_id);
236 self.core.state.borrow_mut().push(state);
237 self.core.event.borrow_mut().push(event);
238 self.core.render.borrow_mut().push(render);
239
240 self.set_top_window();
241 }
242
243 pub fn to_back(&self, n: usize) {
252 for s in self.core.state.borrow().iter() {
253 if s.is_none() {
254 panic!("state is gone");
255 }
256 }
257
258 let type_id = self.core.type_id.borrow_mut().remove(n);
259 let state = self.core.state.borrow_mut().remove(n);
260 let event = self.core.event.borrow_mut().remove(n);
261 let render = self.core.render.borrow_mut().remove(n);
262
263 self.core.type_id.borrow_mut().insert(0, type_id);
264 self.core.state.borrow_mut().insert(0, state);
265 self.core.event.borrow_mut().insert(0, event);
266 self.core.render.borrow_mut().insert(0, render);
267
268 self.set_top_window();
269 }
270
271 fn set_top_window(&self) {
272 let len = self.len();
273
274 if len > 0 {
275 let mut states = self.core.state.borrow_mut();
276 for i in 0..len - 1 {
277 if let Some(s) = &mut states[i] {
278 s.set_top(false);
279 } else {
280 panic!("state is gone");
281 }
282 }
283 if let Some(s) = &mut states[len - 1] {
284 s.set_top(true);
285 } else {
286 panic!("state is gone");
287 }
288 }
289 }
290
291 pub fn is_empty(&self) -> bool {
293 self.core.type_id.borrow().is_empty()
294 }
295
296 pub fn len(&self) -> usize {
298 self.core.len.get()
299 }
300
301 pub fn state_is<S: 'static>(&self, n: usize) -> bool {
303 self.core.type_id.borrow()[n] == TypeId::of::<S>()
304 }
305
306 #[allow(clippy::manual_find)]
308 pub fn top<S: 'static>(&self) -> Option<usize> {
309 for n in (0..self.core.len.get()).rev() {
310 if self.core.type_id.borrow()[n] == TypeId::of::<S>() {
311 return Some(n);
312 }
313 }
314 None
315 }
316
317 pub fn find<S: 'static>(&self) -> Vec<usize> {
319 self.core
320 .type_id
321 .borrow()
322 .iter()
323 .enumerate()
324 .rev()
325 .filter_map(|(n, v)| {
326 if *v == TypeId::of::<S>() {
327 Some(n)
328 } else {
329 None
330 }
331 })
332 .collect()
333 }
334
335 pub fn get<'a, S: 'static>(&'a self, n: usize) -> Ref<'a, S> {
344 self.try_get(n).expect("recursion or wrong type")
345 }
346
347 pub fn get_mut<'a, S: 'static>(&'a self, n: usize) -> RefMut<'a, S> {
356 self.try_get_mut(n).expect("recursion or wrong type")
357 }
358
359 pub fn try_get_mut<'a, S: 'static>(&'a self, n: usize) -> Option<RefMut<'a, S>> {
371 let state = self.core.state.borrow_mut();
372
373 RefMut::filter_map(state, |v| {
374 let state = &mut v[n];
375 if let Some(state) = state.as_mut() {
376 if let Some(state) = (state.as_mut() as &mut dyn Any).downcast_mut::<S>() {
377 Some(state)
378 } else {
379 None
380 }
381 } else {
382 None
383 }
384 })
385 .ok()
386 }
387
388 pub fn try_get<'a, S: 'static>(&'a self, n: usize) -> Option<Ref<'a, S>> {
400 let state = self.core.state.borrow();
401
402 Ref::filter_map(state, |v| {
403 let state = &v[n];
404 if let Some(state) = state.as_ref() {
405 if let Some(state) = (state.as_ref() as &dyn Any).downcast_ref::<S>() {
406 Some(state)
407 } else {
408 None
409 }
410 } else {
411 None
412 }
413 })
414 .ok()
415 }
416}
417
418impl<Event, Context, Error> HandleEvent<Event, &mut Context, Result<WindowControl<Event>, Error>>
424 for WindowList<Event, Context, Error>
425where
426 Event: TryAsRef<crossterm::event::Event>,
427 Error: 'static,
428 Event: 'static,
429{
430 fn handle(&mut self, event: &Event, ctx: &mut Context) -> Result<WindowControl<Event>, Error> {
431 for n in (0..self.core.len.get()).rev() {
432 let (to_front, area) = {
433 let state = self.core.state.borrow();
434 let state = state[n].as_ref().expect("state is gone");
435 match event.try_as_ref() {
436 Some(ct_event!(mouse down Left for x,y))
437 if state.area().contains((*x, *y).into()) =>
438 {
439 (true, state.area())
440 }
441 _ => (false, state.area()),
442 }
443 };
444
445 let Some(mut state) = self.core.state.borrow_mut()[n].take() else {
446 panic!("state is gone");
447 };
448 let event_fn = mem::replace(
449 &mut self.core.event.borrow_mut()[n],
450 Box::new(|_, _, _| Ok(WindowControl::Continue)),
451 );
452
453 let r = event_fn(event, state.as_mut(), ctx);
454
455 self.core.event.borrow_mut()[n] = event_fn;
456 self.core.state.borrow_mut()[n] = Some(state);
457
458 if to_front {
459 self.to_front(n);
460 }
461
462 match r {
463 Ok(r) => match r {
464 WindowControl::Close(_) => {
465 self.close(n);
466 return Ok(r);
467 }
468 WindowControl::Event(_) => {
469 return Ok(r);
470 }
471 WindowControl::Unchanged => {
472 return Ok(r);
473 }
474 WindowControl::Changed => {
475 return Ok(r);
476 }
477 WindowControl::Continue => match event.try_as_ref() {
478 Some(event) => {
479 if mouse_trap(event, area).is_consumed() {
480 return Ok(WindowControl::Unchanged);
481 }
482 }
483 _ => {}
484 },
485 },
486 Err(e) => return Err(e),
487 }
488 }
489
490 Ok(WindowControl::Continue)
491 }
492}
493
494pub fn handle_window_list<Event, Context, Error>(
500 mut window_list: WindowList<Event, Context, Error>,
501 event: &Event,
502 ctx: &mut Context,
503) -> Result<WindowControl<Event>, Error>
504where
505 Event: TryAsRef<crossterm::event::Event>,
506 Error: 'static,
507 Event: 'static,
508 Error: Debug,
509 Event: Debug,
510{
511 window_list.handle(event, ctx)
512}