duat_core/ui/
window.rs

1//! The [`Window`]s of Duat
2//!
3//! In Duat, there is a [`Windows`] struct (accessible via
4//! [`context::windows`]), which holds [`Window`]s. Each `Window`
5//! represents a set of [`Widget`]s that should be displayed at the
6//! same time, like a browser tab.
7//!
8//! These [`Widget`]s will be contained in [`Node`]s, which are an
9//! anonymized version of [`Handle`]s, which the end user interacts
10//! with through the [`Pass`] struct, allowing for massively
11//! desynchronized global state accessibility.
12use std::{
13    any::type_name,
14    iter::Chain,
15    sync::{Arc, Mutex},
16};
17
18use super::{Node, Widget, layout::Layout};
19use crate::{
20    buffer::{Buffer, PathKind},
21    context::{self, Cache, Handle},
22    data::{Pass, RwData},
23    hook::{self, BufferClosed, WidgetCreated, WindowCreated},
24    mode,
25    opts::PrintOpts,
26    session::UiMouseEvent,
27    text::{Text, txt},
28    ui::{Coord, DynSpawnSpecs, PushSpecs, RwArea, SpawnId, StaticSpawnSpecs, Ui},
29};
30
31/// A list of all [`Window`]s in Duat
32pub struct Windows {
33    inner: RwData<InnerWindows>,
34    spawns_to_remove: Mutex<Vec<SpawnId>>,
35    ui: Ui,
36}
37
38/// Inner holder of [`Window`]s
39struct InnerWindows {
40    layout: Box<Mutex<dyn Layout>>,
41    list: Vec<Window>,
42    new_additions: Arc<Mutex<Option<Vec<(usize, Node)>>>>,
43    cur_buffer: RwData<Handle>,
44    cur_widget: RwData<Node>,
45    cur_win: usize,
46    buffer_history: BufferHistory,
47}
48
49impl Windows {
50    /// Initializes the `Windows`, returning a [`Node`] for the first
51    /// [`Buffer`]
52    pub(crate) fn initialize(
53        pa: &mut Pass,
54        buffer: Buffer,
55        layout: Box<Mutex<dyn Layout>>,
56        ui: Ui,
57    ) {
58        let new_additions = Arc::new(Mutex::default());
59        let (window, node) = Window::new(0, pa, ui, buffer, new_additions.clone());
60
61        context::set_windows(Self {
62            inner: RwData::new(InnerWindows {
63                layout,
64                list: vec![window.clone()],
65                new_additions,
66                cur_buffer: RwData::new(node.try_downcast().unwrap()),
67                cur_widget: RwData::new(node.clone()),
68                cur_win: 0,
69                buffer_history: BufferHistory::default(),
70            }),
71            spawns_to_remove: Mutex::new(Vec::new()),
72            ui,
73        });
74
75        hook::trigger(
76            pa,
77            WidgetCreated(node.handle().try_downcast::<Buffer>().unwrap()),
78        );
79        hook::trigger(pa, WindowCreated(window));
80    }
81
82    ////////// Functions for new Widgets
83
84    /// Creates a new list of [`Window`]s, with a main one
85    /// initialiazed
86    pub(crate) fn new_window(&self, pa: &mut Pass, buffer: Buffer) -> Node {
87        let win = self.inner.read(pa).list.len();
88        let new_additions = self.inner.read(pa).new_additions.clone();
89        let (window, node) = Window::new(win, pa, self.ui, buffer, new_additions);
90
91        let inner = self.inner.write(pa);
92        inner.list.push(window);
93
94        hook::trigger(
95            pa,
96            WidgetCreated(node.handle().try_downcast::<Buffer>().unwrap()),
97        );
98        hook::trigger(pa, WindowCreated(self.inner.read(pa).list[win].clone()));
99
100        node
101    }
102
103    /// Push a [`Widget`] to [`Handle`]
104    pub(crate) fn push_widget<W: Widget>(
105        &self,
106        pa: &mut Pass,
107        (target, on_buffers, specs): (&RwArea, Option<bool>, PushSpecs),
108        widget: W,
109        master: Option<&RwArea>,
110    ) -> Option<Handle<W>> {
111        self.push(pa, (target, on_buffers, specs), widget, master)?
112            .handle()
113            .try_downcast()
114    }
115
116    /// Spawn a [`Widget`] on a [`Handle`]
117    ///
118    /// Can fail if the `Handle` in question was already removed.
119    pub(crate) fn spawn_on_widget<W: Widget>(
120        &self,
121        pa: &mut Pass,
122        (target, specs): (&RwArea, DynSpawnSpecs),
123        widget: W,
124    ) -> Option<Handle<W>> {
125        let (win, cluster_master, master) =
126            self.inner
127                .read(pa)
128                .list
129                .iter()
130                .enumerate()
131                .find_map(|(win, window)| {
132                    let inner = window.0.read(pa);
133                    let master = window.nodes(pa).find_map(|node| {
134                        node.area()
135                            .area_is_eq(pa, target)
136                            .then(|| node.handle().clone())
137                    });
138
139                    if inner.master_area.is_master_of(pa, target) {
140                        Some((win, None, master))
141                    } else if let Some((_, node)) = inner
142                        .spawned
143                        .iter()
144                        .find(|(_, node)| node.area().is_master_of(pa, target))
145                    {
146                        Some((win, node.area().get_cluster_master(pa), master))
147                    } else {
148                        None
149                    }
150                })?;
151
152        let widget = RwData::new(widget);
153        let id = SpawnId::new();
154
155        let path = widget
156            .read_as::<Buffer>(pa)
157            .and_then(|buffer| buffer.path_set());
158        let spawned = cluster_master.as_ref().unwrap_or(target).spawn(
159            pa,
160            path.as_ref().map(|p| p.as_ref()),
161            id,
162            specs,
163        )?;
164
165        let node = Node::new(widget, spawned, master);
166
167        let window = self.inner.write(pa).list.remove(win);
168        window.add(pa, node.clone(), None, Location::Spawned(id));
169        self.inner.write(pa).list.insert(win, window);
170
171        hook::trigger(
172            pa,
173            WidgetCreated(node.handle().try_downcast::<W>().unwrap()),
174        );
175
176        node.handle().try_downcast()
177    }
178
179    /// Spawns a [`Widget`] on [`Text`]
180    pub(crate) fn spawn_on_text<W: Widget>(
181        &self,
182        pa: &mut Pass,
183        (id, specs): (SpawnId, DynSpawnSpecs),
184        widget: W,
185        win: usize,
186        master: Handle<dyn Widget>,
187    ) -> Handle<W> {
188        let widget = RwData::new(widget);
189        let path = widget
190            .read_as::<Buffer>(pa)
191            .and_then(|buffer| buffer.path_set());
192        let spawned = self
193            .ui
194            .new_dyn_spawned(path.as_ref().map(|p| p.as_ref()), id, specs, win);
195
196        let node = Node::new(widget, spawned, Some(master));
197
198        let window = self.inner.write(pa).list.remove(win);
199        window.add(pa, node.clone(), None, Location::Spawned(id));
200        self.inner.write(pa).list.insert(win, window);
201
202        hook::trigger(
203            pa,
204            WidgetCreated(node.handle().try_downcast::<W>().unwrap()),
205        );
206
207        node.handle().try_downcast().unwrap()
208    }
209
210    fn spawn_static<W: Widget>(
211        &self,
212        pa: &mut Pass,
213        (specs, win): (StaticSpawnSpecs, usize),
214        widget: W,
215    ) -> Option<Handle<W>> {
216        let id = SpawnId::new();
217        let widget = RwData::new(widget);
218        let path = widget
219            .read_as::<Buffer>(pa)
220            .and_then(|buffer| buffer.path_set());
221        let spawned = self
222            .ui
223            .new_static_spawned(path.as_ref().map(|p| p.as_ref()), id, specs, win);
224
225        let node = Node::new(widget, spawned, None);
226
227        let window = self.inner.write(pa).list.remove(win);
228        window.add(pa, node.clone(), None, Location::Spawned(id));
229        self.inner.write(pa).list.insert(win, window);
230
231        hook::trigger(
232            pa,
233            WidgetCreated(node.handle().try_downcast::<W>().unwrap()),
234        );
235
236        node.handle().try_downcast()
237    }
238
239    /// Pushes a [`Buffer`] to the buffer's parent
240    ///
241    /// This function will push to the edge of `self.buffers_parent`
242    /// This is an area, usually in the center, that contains all
243    /// [`Buffer`]s, and their associated [`Widget`]s,
244    /// with others being at the perifery of this area.
245    pub(crate) fn new_buffer(&self, pa: &mut Pass, buffer: Buffer) -> Node {
246        let inner = self.inner.read(pa);
247        let (handle, specs) = inner.layout.lock().unwrap().new_buffer(pa, &inner.list);
248
249        let specs = PushSpecs { cluster: false, ..specs };
250
251        if let Some(master) = handle.area().get_cluster_master(pa) {
252            self.push(pa, (&master, Some(true), specs), buffer, None)
253                .unwrap()
254        } else {
255            self.push(pa, (&handle.area, Some(true), specs), buffer, None)
256                .unwrap()
257        }
258    }
259
260    /// Pushes a [`Widget`] to the [`Window`]s
261    ///
262    /// May return [`None`] if the [`Area`] was already deleted.
263    fn push<W: Widget>(
264        &self,
265        pa: &mut Pass,
266        (target, on_buffers, mut specs): (&RwArea, Option<bool>, PushSpecs),
267        widget: W,
268        master: Option<&RwArea>,
269    ) -> Option<Node> {
270        let inner = self.inner.read(pa);
271        let win = inner
272            .list
273            .iter()
274            .position(|window| {
275                window.0.read(pa).master_area.is_master_of(pa, target)
276                    || window
277                        .nodes(pa)
278                        .any(|node| node.area().is_master_of(pa, target))
279            })
280            .unwrap();
281
282        let inner_window = inner.list[win].0.read(pa);
283        let target_is_on_buffers = inner_window.buffers_area.is_master_of(pa, target);
284
285        let on_buffers = on_buffers.unwrap_or(target_is_on_buffers) && target_is_on_buffers;
286
287        if target_is_on_buffers && !on_buffers {
288            specs.cluster = false;
289        }
290
291        let location = if on_buffers {
292            Location::OnBuffers
293        } else if let Some((id, _)) = inner_window
294            .spawned
295            .iter()
296            .find(|(_, node)| node.area().area_is_eq(pa, target))
297        {
298            Location::Spawned(*id)
299        } else {
300            Location::Regular
301        };
302
303        let widget = RwData::new(widget);
304        let path = widget
305            .read_as::<Buffer>(pa)
306            .and_then(|buffer| buffer.path_set());
307        let (pushed, parent) =
308            target.push(pa, path.as_ref().map(|p| p.as_ref()), specs, on_buffers)?;
309
310        let master = master.and_then(|area| {
311            self.entries(pa).find_map(|(.., node)| {
312                node.area()
313                    .area_is_eq(pa, area)
314                    .then(|| node.handle().clone())
315            })
316        });
317
318        let node = Node::new(widget, pushed, master);
319
320        let window = self.inner.write(pa).list.remove(win);
321        window.add(pa, node.clone(), parent, location);
322        self.inner.write(pa).list.insert(win, window);
323
324        hook::trigger(
325            pa,
326            WidgetCreated(node.handle().try_downcast::<W>().unwrap()),
327        );
328
329        Some(node)
330    }
331
332    ////////// Existing Widget manipulation
333
334    /// Closes a [`Handle`], removing it from the ui
335    pub(crate) fn close<W: Widget + ?Sized, S>(
336        &self,
337        pa: &mut Pass,
338        handle: &Handle<W, S>,
339    ) -> Result<(), Text> {
340        let win = self.handle_window(pa, handle)?;
341
342        // If it's a Buffer, swap all buffers ahead, so this one becomes the
343        // last.
344        if let Some(buf_handle) = handle.try_downcast::<Buffer>() {
345            hook::trigger(pa, BufferClosed((buf_handle.clone(), Cache::new())));
346
347            let buffers_ahead: Vec<Node> = self.inner.read(pa).list[win]
348                .nodes(pa)
349                .filter(|node| {
350                    node.handle().read_as::<Buffer>(pa).is_some_and(|buffer| {
351                        buffer.layout_order > buf_handle.read(pa).layout_order
352                    })
353                })
354                .cloned()
355                .collect();
356
357            for buffer_ahead in buffers_ahead {
358                self.swap(pa, handle, buffer_ahead.handle())?;
359            }
360        }
361
362        // Actually removing the Handle.
363        let mut list = std::mem::take(&mut self.inner.write(pa).list);
364
365        if list[win].close(pa, handle) {
366            list.remove(win);
367            self.ui.remove_window(win);
368            let cur_win = context::current_win_index(pa);
369            if cur_win > win {
370                self.inner.write(pa).cur_win -= 1;
371            }
372        }
373
374        let inner = self.inner.write(pa);
375        inner.list = list;
376        inner.new_additions.lock().unwrap().get_or_insert_default();
377
378        // If this is the active Handle, pick another one to make active.
379        let inner = self.inner.read(pa);
380        if handle == inner.cur_widget.read(pa).handle() || handle == inner.cur_buffer.read(pa) {
381            if let Some(handle) = handle.try_downcast::<Buffer>() {
382                self.inner.write(pa).buffer_history.remove(&handle);
383
384                let entry = self
385                    .inner
386                    .write(pa)
387                    .buffer_history
388                    .jump_by(handle.clone(), -1)
389                    .or_else(|| self.buffers(pa).next())
390                    .and_then(|handle| {
391                        self.entries(pa).find_map(|(win, node)| {
392                            (*node.handle() == handle).then(|| (win, node.clone()))
393                        })
394                    });
395
396                if let Some((_, node)) = entry {
397                    crate::mode::reset_to(node.handle().clone());
398                } else {
399                    // If there is no previous Buffer, just quit.
400                    context::sender()
401                        .send(crate::session::DuatEvent::Quit)
402                        .unwrap();
403                    return Ok(());
404                }
405            } else {
406                crate::mode::reset_to(inner.cur_buffer.read(pa).to_dyn());
407            }
408        }
409
410        Ok(())
411    }
412
413    /// Swaps two [`Handle`]'s positions
414    pub(crate) fn swap<W1: Widget + ?Sized, S1, W2: Widget + ?Sized, S2>(
415        &self,
416        pa: &mut Pass,
417        lhs: &Handle<W1, S1>,
418        rhs: &Handle<W2, S2>,
419    ) -> Result<(), Text> {
420        let lhs_win = self.handle_window(pa, lhs)?;
421        let rhs_win = self.handle_window(pa, rhs)?;
422
423        let [lhs_buffer, rhs_buffer] = [lhs.try_downcast::<Buffer>(), rhs.try_downcast()];
424
425        if let [Some(lhs), Some(rhs)] = [lhs_buffer, rhs_buffer] {
426            let lhs_lo = lhs.read(pa).layout_order;
427            let rhs_lo = std::mem::replace(&mut rhs.write(pa).layout_order, lhs_lo);
428            lhs.write(pa).layout_order = rhs_lo
429        }
430
431        let windows = std::mem::take(&mut self.inner.write(pa).list);
432
433        let lhs_nodes = windows[lhs_win].take_with_related_nodes(pa, lhs);
434        windows[rhs_win].insert_nodes(pa, lhs_nodes);
435
436        let rhs_nodes = windows[rhs_win].take_with_related_nodes(pa, rhs);
437        windows[lhs_win].insert_nodes(pa, rhs_nodes);
438
439        let wins = self.inner.write(pa);
440        wins.list = windows;
441        wins.new_additions.lock().unwrap().get_or_insert_default();
442
443        lhs.area().swap(pa, rhs.area());
444
445        let cur_buffer = context::current_buffer(pa);
446        if lhs_win != rhs_win {
447            if lhs == cur_buffer {
448                self.inner.write(pa).cur_win = lhs_win;
449                self.ui.switch_window(lhs_win);
450            } else if rhs == cur_buffer {
451                self.inner.write(pa).cur_win = rhs_win;
452                self.ui.switch_window(rhs_win);
453            }
454        }
455
456        Ok(())
457    }
458
459    /// Opens a new [`Buffer`] on a new [`Window`], or moves it there,
460    /// if it is already open
461    pub(crate) fn open_or_move_to_new_window(
462        &self,
463        pa: &mut Pass,
464        pk: PathKind,
465        default_buffer_cfg: PrintOpts,
466    ) -> Node {
467        let node = match self.buffer_entry(pa, pk.clone()) {
468            Ok((win, handle)) if self.get(pa, win).unwrap().buffers(pa).len() > 1 => {
469                // Take the nodes in the original Window
470                handle.write(pa).layout_order = 0;
471
472                let nodes = {
473                    let old_window = self.inner.write(pa).list.remove(win);
474                    let nodes = old_window.take_with_related_nodes(pa, &handle.to_dyn());
475                    self.inner.write(pa).list.insert(win, old_window);
476
477                    nodes
478                };
479
480                // Create a new Window Swapping the new root with buffers_area
481                let path = handle.read(pa).path_set();
482                let new_root = self.ui.new_root(path.as_ref().map(|p| p.as_ref()));
483                handle.area().swap(pa, &new_root);
484                let window = Window::new_from_raw(
485                    pa,
486                    win,
487                    handle.area.clone(),
488                    nodes,
489                    self.inner.read(pa).new_additions.clone(),
490                );
491
492                self.inner.write(pa).list.push(window.clone());
493
494                hook::trigger(pa, WindowCreated(window));
495
496                // Swap the Buffers ahead of the swapped new_root
497                let lo = handle.read(pa).layout_order;
498
499                for handle in &self.inner.read(pa).list[win].buffers(pa)[lo..] {
500                    new_root.swap(pa, handle.area());
501                }
502
503                // Delete the new_root, which should be the last "Buffer" in the
504                // list of the original Window.
505                new_root.delete(pa);
506
507                self.inner
508                    .write(pa)
509                    .new_additions
510                    .lock()
511                    .unwrap()
512                    .get_or_insert_default();
513
514                Node::from_handle(handle)
515            }
516            // The Handle in question is already in its own window, so no need
517            // to move it to another one.
518            Ok((.., handle)) => Node::from_handle(handle),
519            Err(_) => self.new_window(pa, Buffer::new(pk.as_path(), default_buffer_cfg)),
520        };
521
522        if context::current_buffer(pa).read(pa).path_kind() != pk {
523            mode::reset_to(node.handle().clone());
524        }
525
526        node
527    }
528
529    /// Sets the current active [`Handle`]
530    pub(crate) fn set_current_node(&self, pa: &mut Pass, node: Node) -> Result<(), Text> {
531        // SAFETY: This Pass is only used when I'm already reborrowing a &mut
532        // Pass, and it is known that it only writes to other types.
533        let internal_pass = &mut unsafe { Pass::new() };
534
535        let win = self.handle_window(pa, node.handle())?;
536        let inner = self.inner.write(pa);
537
538        if let Some(handle) = node.try_downcast::<Buffer>() {
539            let current = std::mem::replace(inner.cur_buffer.write(internal_pass), handle.clone());
540            inner.buffer_history.insert(current, handle);
541        }
542        *inner.cur_widget.write(internal_pass) = node.clone();
543        inner.cur_win = win;
544        self.ui.switch_window(win);
545
546        Ok(())
547    }
548
549    ////////// Spawned Widget cleanup
550
551    /// Adds a [`SpawnId`] to be removed when a [`Pass`] is available
552    pub(crate) fn queue_close_spawned(&self, id: SpawnId) {
553        let mut spawns_to_remove = self.spawns_to_remove.lock().unwrap();
554        if !spawns_to_remove.contains(&id) {
555            spawns_to_remove.push(id)
556        }
557    }
558
559    /// Removes all [`SpawnId`]'s [`Widget`]s which were queued for
560    /// closure
561    pub(crate) fn cleanup_despawned(&self, pa: &mut Pass) {
562        let spawns_to_remove = std::mem::take(&mut *self.spawns_to_remove.lock().unwrap());
563        for id in spawns_to_remove {
564            if let Some((_, node)) = self
565                .iter(pa)
566                .flat_map(|window| &window.0.read(pa).spawned)
567                .find(|(other, _)| *other == id)
568            {
569                self.close(pa, &node.handle().clone()).unwrap();
570            }
571        }
572    }
573
574    ////////// Entry lookup
575
576    /// An entry for a [`Handle`]
577    pub(crate) fn handle_window<W: Widget + ?Sized, S>(
578        &self,
579        pa: &Pass,
580        handle: &Handle<W, S>,
581    ) -> Result<usize, Text> {
582        self.entries(pa)
583            .find_map(|(win, node)| (node.handle() == handle).then_some(win))
584            .ok_or_else(|| txt!("The Handle was already closed"))
585    }
586
587    /// An entry for a buffer with the given name
588    pub(crate) fn buffer_entry(&self, pa: &Pass, pk: PathKind) -> Result<(usize, Handle), Text> {
589        self.entries(pa)
590            .find_map(|(win, node)| {
591                (node.read_as(pa).filter(|f: &&Buffer| f.path_kind() == pk))
592                    .and_then(|_| node.try_downcast().map(|handle| (win, handle)))
593            })
594            .ok_or_else(|| txt!("Buffer {pk} not found"))
595    }
596
597    /// An entry for a buffer with the given name
598    pub(crate) fn named_buffer_entry(
599        &self,
600        pa: &Pass,
601        name: &str,
602    ) -> Result<(usize, Handle), Text> {
603        self.entries(pa)
604            .find_map(|(win, node)| {
605                (node.read_as(pa).filter(|f: &&Buffer| f.name() == name))
606                    .and_then(|_| node.try_downcast().map(|handle| (win, handle)))
607            })
608            .ok_or_else(|| txt!("Buffer [buffer]{name}[] not found"))
609    }
610
611    /// An entry for a widget of a specific type
612    ///
613    /// Returns the index of the window, the index of the [`Widget`],
614    /// and the [`Widget`]'s [`Node`]
615    pub(crate) fn node_of<'a, W: Widget>(&'a self, pa: &'a Pass) -> Result<&'a Node, Text> {
616        let handle = context::current_buffer(pa);
617
618        if let Some((handle, _)) = handle.get_related::<W>(pa).next() {
619            self.entries(pa)
620                .find_map(|(.., node)| node.ptr_eq(handle.widget()).then_some(node))
621        } else {
622            let cur_win = self.inner.read(pa).cur_win;
623            let list = &self.inner.read(pa).list;
624            list[cur_win]
625                .nodes(pa)
626                .chain(list[cur_win + 1..].iter().flat_map(|win| win.nodes(pa)))
627                .chain(list[..cur_win].iter().flat_map(|win| win.nodes(pa)))
628                .find(|node| node.data_is::<W>())
629        }
630        .ok_or(txt!("No widget of type [a]{}[] found", type_name::<W>()))
631    }
632
633    ////////// Entry iterators
634
635    /// Iterates over all widget entries, with window indices
636    pub(crate) fn entries<'a>(&'a self, pa: &'a Pass) -> impl Iterator<Item = (usize, &'a Node)> {
637        self.inner
638            .read(pa)
639            .list
640            .iter()
641            .enumerate()
642            .flat_map(|(win, window)| {
643                let inner = window.0.read(pa);
644                inner
645                    .nodes
646                    .iter()
647                    .chain(inner.spawned.iter().map(|(_, node)| node))
648                    .map(move |node| (win, node))
649            })
650    }
651
652    /// Iterates around a specific widget, going forwards
653    pub(crate) fn iter_around<'a>(
654        &'a self,
655        pa: &'a Pass,
656        win: usize,
657        wid: usize,
658    ) -> impl Iterator<Item = (usize, &'a Node)> + 'a {
659        let window_entries =
660            |(w, window): (usize, &'a Window)| window.nodes(pa).map(move |node| (w, node));
661
662        let windows = &self.inner.read(pa).list;
663
664        let prev_len: usize = windows
665            .iter()
666            .take(win)
667            .map(|win| win.len_widgets(pa))
668            .sum();
669
670        windows
671            .iter()
672            .enumerate()
673            .skip(win)
674            .flat_map(window_entries)
675            .skip(wid + 1)
676            .chain(
677                windows
678                    .iter()
679                    .enumerate()
680                    .take(win + 1)
681                    .flat_map(window_entries)
682                    .take(prev_len + wid),
683            )
684    }
685
686    /// Iterates around a specific widget, going backwards
687    pub(crate) fn iter_around_rev<'a>(
688        &'a self,
689        pa: &'a Pass,
690        win: usize,
691        wid: usize,
692    ) -> impl Iterator<Item = (usize, &'a Node)> + 'a {
693        let entries =
694            |(w, window): (usize, &'a Window)| window.nodes(pa).map(move |node| (w, node));
695
696        let windows = &self.inner.read(pa).list;
697
698        let next_len: usize = windows
699            .iter()
700            .skip(win)
701            .map(|win| win.len_widgets(pa))
702            .sum();
703
704        windows
705            .iter()
706            .enumerate()
707            .rev()
708            .skip(windows.len() - (win + 1))
709            .flat_map(move |(w, win)| entries((w, win)).rev().skip(win.len_widgets(pa) - wid))
710            .chain(
711                windows
712                    .iter()
713                    .enumerate()
714                    .rev()
715                    .take(windows.len() - win)
716                    .flat_map(move |(i, win)| entries((i, win)).rev())
717                    .take(next_len - (wid + 1)),
718            )
719    }
720
721    ////////// Buffer switching
722
723    /// Jumps around in the buffer history
724    ///
725    /// This will jump forwards if `number` is positive, backwards
726    /// otherwise.
727    pub fn jump_buffers_by(&self, pa: &mut Pass, jumps: i32) {
728        let current = self.inner.read(pa).cur_buffer.read(pa).clone();
729        if let Some(handle) = self.inner.write(pa).buffer_history.jump_by(current, jumps) {
730            mode::reset_to(handle.to_dyn());
731        } else {
732            context::warn!("No buffer [a]{jumps}[] jumps away from the current one");
733        }
734    }
735
736    /// Jumps to the last buffer
737    ///
738    /// Calling this repeatedly
739    pub fn last_buffer(&self, pa: &mut Pass) -> Result<Handle, Text> {
740        let current = self.inner.read(pa).cur_buffer.read(pa).clone();
741        if let Some(handle) = self.inner.write(pa).buffer_history.last(current) {
742            mode::reset_to(handle.to_dyn());
743            Ok(handle)
744        } else {
745            Err(txt!("No last buffer"))
746        }
747    }
748
749    ////////// Querying functions
750
751    /// The bottom right [`Coord`] on the screen
752    ///
753    /// Since the top left coord is `Coord { x: 0.0, y: 0.0 }`, this
754    /// is also the size of the window.
755    pub fn size(&self) -> Coord {
756        self.ui.size()
757    }
758
759    /// The number of open [`Window`]s
760    ///
761    /// Should never be 0, as that is not a valid state of affairs.
762    pub fn len(&self, pa: &Pass) -> usize {
763        self.inner.read(pa).list.len()
764    }
765
766    /// get's the `win`th [`Window`]
767    pub fn get<'a>(&'a self, pa: &'a Pass, win: usize) -> Option<&'a Window> {
768        self.inner.read(pa).list.get(win)
769    }
770
771    /// Iterates through every [`Window`]
772    pub fn iter<'a>(&'a self, pa: &'a Pass) -> std::slice::Iter<'a, Window> {
773        self.inner.read(pa).list.iter()
774    }
775
776    /// Returns an [`Iterator`] over the [`Handle`]s of Duat
777    pub fn handles<'a>(&'a self, pa: &'a Pass) -> impl Iterator<Item = &'a Handle<dyn Widget>> {
778        self.inner
779            .read(pa)
780            .list
781            .iter()
782            .flat_map(|w| w.nodes(pa).map(|n| n.handle()))
783    }
784
785    /// Returns an [`Iterator`] over the [`Handle`]s of Duat
786    pub fn handles_of<'a, W: Widget>(
787        &'a self,
788        pa: &'a Pass,
789    ) -> impl Iterator<Item = Handle<W>> + 'a {
790        self.inner
791            .read(pa)
792            .list
793            .iter()
794            .flat_map(|w| w.nodes(pa).filter_map(|n| n.handle().try_downcast()))
795    }
796
797    /// Iterates over all [`Handle<Buffer>`]s in Duat
798    pub fn buffers<'a>(&'a self, pa: &'a Pass) -> impl Iterator<Item = Handle> + 'a {
799        self.inner.read(pa).list.iter().flat_map(|w| w.buffers(pa))
800    }
801
802    /// The index of the currently active [`Window`]
803    pub fn current_window(&self, pa: &Pass) -> usize {
804        self.inner.read(pa).cur_win
805    }
806
807    /// The [`RwData`] that points to the currently active [`Buffer`]
808    pub(crate) fn current_buffer<'a>(&'a self, pa: &'a Pass) -> &'a RwData<Handle> {
809        &self.inner.read(pa).cur_buffer
810    }
811
812    /// The [`RwData`] that points to the currently active [`Widget`]
813    pub(crate) fn current_widget<'a>(&'a self, pa: &'a Pass) -> &'a RwData<Node> {
814        &self.inner.read(pa).cur_widget
815    }
816
817    /// Gets the new additions to the [`Windows`]
818    pub(crate) fn get_additions(&self, pa: &mut Pass) -> Option<Vec<(usize, Node)>> {
819        self.inner.write(pa).new_additions.lock().unwrap().take()
820    }
821}
822
823/// A region containing [`Handle`]s
824///
825/// This is like a browser tab, it can contain any number of regular
826/// and spawned [`Handle`]s.
827#[derive(Clone)]
828pub struct Window(RwData<InnerWindow>);
829
830struct InnerWindow {
831    index: usize,
832    nodes: Vec<Node>,
833    spawned: Vec<(SpawnId, Node)>,
834    buffers_area: RwArea,
835    master_area: RwArea,
836    new_additions: Arc<Mutex<Option<Vec<(usize, Node)>>>>,
837}
838
839impl Window {
840    /// Returns a new instance of [`Window`]
841    fn new<W: Widget>(
842        index: usize,
843        pa: &mut Pass,
844        ui: Ui,
845        widget: W,
846        new_additions: Arc<Mutex<Option<Vec<(usize, Node)>>>>,
847    ) -> (Self, Node) {
848        let widget = RwData::new(widget);
849        let path = if let Some(buffer) = widget.write_as::<Buffer>(pa) {
850            buffer.layout_order = get_layout_order();
851            buffer.path_set()
852        } else {
853            None
854        };
855
856        let area = ui.new_root(path.as_ref().map(|p| p.as_ref()));
857        let node = Node::new::<W>(widget, area.clone(), None);
858
859        new_additions
860            .lock()
861            .unwrap()
862            .get_or_insert_default()
863            .push((index, node.clone()));
864
865        let window = Self(RwData::new(InnerWindow {
866            index,
867            nodes: vec![node.clone()],
868            spawned: Vec::new(),
869            buffers_area: area.clone(),
870            master_area: area.clone(),
871            new_additions,
872        }));
873
874        (window, node)
875    }
876
877    /// Returns a new [`Window`] from raw elements
878    pub(crate) fn new_from_raw(
879        pa: &mut Pass,
880        index: usize,
881        master_area: RwArea,
882        nodes: Vec<Node>,
883        new_additions: Arc<Mutex<Option<Vec<(usize, Node)>>>>,
884    ) -> Self {
885        let master_area = master_area
886            .get_cluster_master(pa)
887            .unwrap_or(master_area.clone());
888
889        Self(RwData::new(InnerWindow {
890            index,
891            nodes,
892            spawned: Vec::new(),
893            buffers_area: master_area.clone(),
894            master_area,
895            new_additions,
896        }))
897    }
898
899    ////////// Widget addition/removal
900
901    /// Pushes a [`Widget`] around the "buffer area" of a `Window`
902    ///
903    /// When you push a `Widget`, it is placed on an edge of the
904    /// area, and a new parent area may be created to hold both
905    /// widgets. If created, that new area will be used for pushing
906    /// widgets in the future.
907    ///
908    /// This means that, if you push widget *B* to the bottom, then
909    /// you push widget *A* to the left, you will get this layout:
910    ///
911    /// ```text
912    /// ╭───┬───────────╮
913    /// │   │           │
914    /// │ A │  Buffers  │
915    /// │   │           │
916    /// ├───┴───────────┤
917    /// │       B       │
918    /// ╰───────────────╯
919    /// ```
920    ///
921    /// The `Buffers` region here represents a central area that all
922    /// `Window`s contain, where all the [`Buffer`]s are placed
923    /// alongside their [satellite `Widget`s]. When you push `Widget`s
924    /// to the `Window`, instead of to a [`Handle`], those widgets are
925    /// placed in the outer region, not being associated with any
926    /// particular `Buffer`.
927    ///
928    /// In this case, each `Window` will have a [`LogBook`] on the
929    /// left side as well as [`FooterWidgets`] on the bottom.
930    ///
931    /// [`Buffer`]: crate::buffer::Buffer
932    /// [`LogBook`]: https://docs.rs/duat/latest/duat/widgets/struct.LogBook.html
933    /// [`FooterWidgets`]: https://docs.rs/duat/latest/duat/widgets/struct.FooterWidgets.html
934    /// [`WindowCreated`]: crate::hook::WindowCreated
935    /// [satellite `Widget`s]: context::Handle::push_outer_widget
936    pub fn push_inner<W: Widget>(
937        &self,
938        pa: &mut Pass,
939        widget: W,
940        mut specs: PushSpecs,
941    ) -> Handle<W> {
942        let target = self.0.read(pa).buffers_area.clone();
943
944        specs.cluster = false;
945
946        context::windows()
947            .push_widget(pa, (&target, Some(false), specs), widget, None)
948            .unwrap()
949    }
950
951    /// Pushes a [`Widget`] to the edges of a `Window`
952    ///
953    /// When you push a `Widget`, it is placed on an edge of the
954    /// area, and a new parent area may be created to hold both
955    /// widgets. If created, that new area will be used for pushing
956    /// widgets in the future.
957    ///
958    /// This means that, if you push widget *B* to the bottom, then
959    /// you push widget *A* to the left, you will get this layout:
960    ///
961    /// ```text
962    /// ╭───┬───────────╮
963    /// │   │           │
964    /// │   │  Buffers  │
965    /// │ A │           │
966    /// │   ├───────────┤
967    /// │   │     B     │
968    /// ╰───┴───────────╯
969    /// ```
970    ///
971    /// The `Buffers` region here represents a central area that all
972    /// `Window`s contain, where all the [`Buffer`]s are placed
973    /// alongside their [satellite `Widget`s]. When you push `Widget`s
974    /// to the `Window`, instead of to a [`Handle`], those widgets are
975    /// placed in the outer region, not being associated with any
976    /// particular `Buffer`.
977    ///
978    /// In this case, each `Window` will have a [`LogBook`] on the
979    /// left side as well as [`FooterWidgets`] on the bottom.
980    ///
981    /// [`Buffer`]: crate::buffer::Buffer
982    /// [`LogBook`]: https://docs.rs/duat/latest/duat/widgets/struct.LogBook.html
983    /// [`FooterWidgets`]: https://docs.rs/duat/latest/duat/widgets/struct.FooterWidgets.html
984    /// [`WindowCreated`]: crate::hook::WindowCreated
985    /// [satellite `Widget`s]: context::Handle::push_outer_widget
986    pub fn push_outer<W: Widget>(
987        &self,
988        pa: &mut Pass,
989        widget: W,
990        mut specs: PushSpecs,
991    ) -> Handle<W> {
992        let target = self.0.read(pa).master_area.clone();
993
994        specs.cluster = false;
995
996        context::windows()
997            .push_widget(pa, (&target, Some(false), specs), widget, None)
998            .unwrap()
999    }
1000
1001    /// Spawns a new static [`Widget`] on this `Window`
1002    ///
1003    /// This `Widget`, unlike all other kinds, does not follow changes
1004    /// in the layout by the resizing or closure of other `Widget`s.
1005    /// It instead stays in a single [`Coord`], its width and height
1006    /// being predefined.
1007    ///
1008    /// There is one circumstance in which this `Widget` will move,
1009    /// however: when the window resizes. In this circumstance, the
1010    /// `Widget` will be relocated as to be placed in relatively the
1011    /// same place on screen, in relation to the bottom right corner
1012    /// of the screen.
1013    ///
1014    /// [`Coord`]: super::Coord
1015    pub fn spawn<W: Widget>(&self, pa: &mut Pass, widget: W, specs: StaticSpawnSpecs) -> Handle<W> {
1016        context::windows()
1017            .spawn_static(pa, (specs, self.0.read(pa).index), widget)
1018            .unwrap()
1019    }
1020
1021    /// Adds a [`Widget`] to the list of widgets of this [`Window`]
1022    fn add(&self, pa: &mut Pass, node: Node, parent: Option<RwArea>, location: Location) {
1023        match location {
1024            Location::OnBuffers => {
1025                self.0.write(pa).nodes.push(node.clone());
1026                if let Some(parent) = &parent
1027                    && parent.is_master_of(pa, &self.0.read(pa).buffers_area)
1028                {
1029                    self.0.write(pa).buffers_area = parent.clone()
1030                }
1031            }
1032            Location::Regular => self.0.write(pa).nodes.push(node.clone()),
1033            Location::Spawned(id) => self.0.write(pa).spawned.push((id, node.clone())),
1034        }
1035
1036        if let Some(parent) = &parent
1037            && parent.is_master_of(pa, &self.0.read(pa).master_area)
1038        {
1039            self.0.write(pa).master_area = parent.clone()
1040        }
1041
1042        let inner = self.0.write(pa);
1043        inner
1044            .new_additions
1045            .lock()
1046            .unwrap()
1047            .get_or_insert_default()
1048            .push((inner.index, node.clone()));
1049    }
1050
1051    /// Closes the [`Handle`] and all related ones
1052    ///
1053    /// Returns `true` if this `Window` is supposed to be removed.
1054    fn close<W: Widget + ?Sized, S>(&self, pa: &mut Pass, handle: &Handle<W, S>) -> bool {
1055        let handle_eq = |node: &mut Node| node.handle() == handle;
1056
1057        let inner = self.0.write(pa);
1058
1059        let node = if let Some(node) = inner.nodes.extract_if(.., handle_eq).next() {
1060            node
1061        } else if let Some((_, node)) = inner.spawned.extract_if(.., |(_, n)| handle_eq(n)).next() {
1062            node
1063        } else {
1064            unreachable!("This isn't supposed to fail");
1065        };
1066
1067        node.handle().declare_closed(pa);
1068
1069        let (do_rm_window, rm_areas) = node.area().delete(pa);
1070        if do_rm_window {
1071            for handle in self.handles(pa).cloned().collect::<Vec<_>>() {
1072                handle.declare_closed(pa);
1073            }
1074            return true;
1075        }
1076
1077        let (mut nodes, mut spawned) = {
1078            let inner = self.0.write(pa);
1079            let nodes = std::mem::take(&mut inner.nodes);
1080            let spawned = std::mem::take(&mut inner.spawned);
1081            (nodes, spawned)
1082        };
1083
1084        nodes.retain(|node| {
1085            if rm_areas
1086                .iter()
1087                .any(|a| a.area_is_eq(pa, node.handle().area()))
1088            {
1089                node.handle().declare_closed(pa);
1090                false
1091            } else {
1092                true
1093            }
1094        });
1095        spawned.retain(|(_, node)| {
1096            if rm_areas
1097                .iter()
1098                .any(|a| a.area_is_eq(pa, node.handle().area()))
1099            {
1100                node.handle().declare_closed(pa);
1101                false
1102            } else {
1103                true
1104            }
1105        });
1106
1107        let inner = self.0.write(pa);
1108        inner.nodes = nodes;
1109        inner.spawned = spawned;
1110
1111        let buffers = self.buffers(pa);
1112        if buffers.len() == 1 {
1113            let handle = buffers.first().unwrap();
1114
1115            let master_area = handle
1116                .area()
1117                .get_cluster_master(pa)
1118                .unwrap_or(handle.area.clone());
1119
1120            self.0.write(pa).buffers_area = master_area;
1121        }
1122
1123        if self.buffers(pa).is_empty() {
1124            for handle in self.handles(pa).cloned().collect::<Vec<_>>() {
1125                handle.declare_closed(pa);
1126            }
1127            true
1128        } else {
1129            false
1130        }
1131    }
1132
1133    /// Takes all [`Node`]s related to a given [`Node`]
1134    fn take_with_related_nodes<W: Widget + ?Sized, S>(
1135        &self,
1136        pa: &mut Pass,
1137        handle: &Handle<W, S>,
1138    ) -> Vec<Node> {
1139        let related = handle.related();
1140
1141        let (related, inner) = pa.read_and_write(related, &self.0);
1142
1143        inner
1144            .nodes
1145            .extract_if(.., |node| {
1146                related.iter().any(|(handle, _)| handle == node.handle()) || node.handle() == handle
1147            })
1148            .collect()
1149    }
1150
1151    /// Inserts [`Buffer`] nodes orderly
1152    fn insert_nodes(&self, pa: &mut Pass, nodes: Vec<Node>) {
1153        self.0.write(pa).nodes.extend(nodes);
1154    }
1155
1156    ////////// Querying functions
1157
1158    /// An [`Iterator`] over the [`Node`]s in a [`Window`]
1159    pub(crate) fn nodes<'a>(&'a self, pa: &'a Pass) -> Nodes<'a> {
1160        let inner = self.0.read(pa);
1161
1162        let spawned = SpawnedNodes { iter: inner.spawned.iter() };
1163
1164        Nodes {
1165            iter: inner.nodes.iter().chain(spawned),
1166            len: inner.nodes.len() + inner.spawned.len(),
1167            taken: 0,
1168        }
1169    }
1170
1171    /// An [`Iterator`] over all [`Handle`]s in a `Window`
1172    ///
1173    /// Each `Handle` takes care of one [`Widget`], if you want to see
1174    /// which one exactly is being used, you can use the
1175    /// [`Handle::try_downcast`] and [`Handle::read_as`] methods.
1176    ///
1177    /// If you just want an iterator over the [`Buffer`]s, then check
1178    /// out [`Window::buffers`].
1179    pub fn handles<'a>(&'a self, pa: &'a Pass) -> impl Iterator<Item = &'a Handle<dyn Widget>> {
1180        self.nodes(pa).map(|node| node.handle())
1181    }
1182
1183    /// The [`Buffer`]s in a single `Window`
1184    ///
1185    /// They will be ordered by where the `"next-buffer"` [command]
1186    /// focus on. This usually follows the order by which they were
1187    /// created, but it can be altered if you use the `"swap"`
1188    /// command.
1189    ///
1190    /// If you want an [`Iterator`] over all [`Handle`]s, see
1191    /// [`Window::handles`].
1192    ///
1193    /// [command]: crate::cmd
1194    pub fn buffers(&self, pa: &Pass) -> Vec<Handle> {
1195        let inner = self.0.read(pa);
1196        let mut buffers: Vec<Handle> = inner
1197            .nodes
1198            .iter()
1199            .filter_map(|node| node.try_downcast())
1200            .collect();
1201
1202        buffers.sort_unstable_by_key(|buffer| buffer.read(pa).layout_order);
1203
1204        buffers.extend(
1205            inner
1206                .spawned
1207                .iter()
1208                .filter_map(|(_, node)| node.try_downcast()),
1209        );
1210
1211        buffers
1212    }
1213
1214    pub(crate) fn send_mouse_event(&self, pa: &mut Pass, mouse_event: UiMouseEvent) {
1215        let inner = self.0.read(pa);
1216        let node = inner
1217            .spawned
1218            .iter()
1219            .rev()
1220            .map(|(_, node)| node)
1221            .chain(&inner.nodes)
1222            .find(|node| {
1223                let tl = node.handle().area().top_left(pa);
1224                let br = node.handle().area().bottom_right(pa);
1225                (tl.x <= mouse_event.coord.x && tl.y <= mouse_event.coord.y)
1226                    && (mouse_event.coord.x < br.x && mouse_event.coord.y < br.y)
1227            })
1228            .cloned();
1229
1230        if let Some(node) = node {
1231            node.on_mouse_event(pa, mouse_event);
1232        }
1233    }
1234
1235    /// How many [`Widget`]s are in this [`Window`]
1236    pub(crate) fn len_widgets(&self, pa: &Pass) -> usize {
1237        let inner = self.0.read(pa);
1238        inner.nodes.len() + inner.spawned.len()
1239    }
1240}
1241
1242#[derive(Default)]
1243struct BufferHistory {
1244    current_i: usize,
1245    list: Vec<Handle>,
1246    last: Option<Handle>,
1247}
1248
1249impl BufferHistory {
1250    /// Returns the previous [`Handle`], if there is one
1251    fn jump_by(&mut self, current: Handle, by: i32) -> Option<Handle> {
1252        let new_i = self
1253            .current_i
1254            .saturating_add_signed(by as isize)
1255            .min(self.list.len());
1256        let new_handle = self.list.get(new_i)?.clone();
1257
1258        self.last = Some(current);
1259        self.current_i = new_i;
1260        Some(new_handle)
1261    }
1262
1263    /// Returns the last [`Handle`]
1264    ///
1265    /// Repeatedly calling this function will return the same two
1266    /// [`Handle`]s.
1267    fn last(&mut self, current: Handle) -> Option<Handle> {
1268        if let Some(last) = self.last.as_mut() {
1269            Some(std::mem::replace(last, current))
1270        } else if let Some(last) = self.list.get(self.current_i.checked_sub(1)?) {
1271            self.last = Some(current);
1272            Some(last.clone())
1273        } else {
1274            None
1275        }
1276    }
1277
1278    /// Inserts a new entry, but only if it is different from both of
1279    /// the surrounding entries
1280    fn insert(&mut self, current: Handle, handle: Handle) {
1281        if self
1282            .current_i
1283            .checked_sub(1)
1284            .is_none_or(|prev_i| self.list[prev_i] != handle)
1285            && self
1286                .list
1287                .get(self.current_i)
1288                .is_none_or(|other| *other != handle)
1289        {
1290            self.list.insert(self.current_i, handle);
1291            self.last = Some(current);
1292            self.current_i += 1;
1293        }
1294    }
1295
1296    /// Clears all instances of a given [`Handle`], signaling that it
1297    /// has been closed
1298    fn remove(&mut self, handle: &Handle) {
1299        let mut i = 0;
1300        self.list.retain(|other| {
1301            if other == handle {
1302                if i < self.current_i {
1303                    self.current_i -= 1;
1304                }
1305                false
1306            } else {
1307                i += 1;
1308                true
1309            }
1310        });
1311    }
1312}
1313
1314/// Returns a new layout order, which will be different from every
1315/// other
1316fn get_layout_order() -> usize {
1317    use std::sync::atomic::{AtomicUsize, Ordering};
1318
1319    static LAYOUT_ORDER: AtomicUsize = AtomicUsize::new(0);
1320    LAYOUT_ORDER.fetch_add(1, Ordering::Relaxed)
1321}
1322
1323enum Location {
1324    OnBuffers,
1325    Regular,
1326    Spawned(SpawnId),
1327}
1328
1329#[derive(Debug, Clone)]
1330pub(crate) struct Nodes<'a> {
1331    iter: Chain<std::slice::Iter<'a, Node>, SpawnedNodes<'a>>,
1332    len: usize,
1333    taken: usize,
1334}
1335
1336impl<'a> Iterator for Nodes<'a> {
1337    type Item = &'a Node;
1338
1339    fn next(&mut self) -> Option<Self::Item> {
1340        let next = self.iter.next();
1341        self.taken += next.is_some() as usize;
1342        next
1343    }
1344
1345    fn size_hint(&self) -> (usize, Option<usize>) {
1346        (self.len - self.taken, Some(self.len - self.taken))
1347    }
1348}
1349
1350impl<'a> DoubleEndedIterator for Nodes<'a> {
1351    fn next_back(&mut self) -> Option<Self::Item> {
1352        let next = self.iter.next_back();
1353        self.taken += next.is_some() as usize;
1354        next
1355    }
1356}
1357
1358impl ExactSizeIterator for Nodes<'_> {}
1359
1360#[derive(Debug, Clone)]
1361struct SpawnedNodes<'a> {
1362    iter: std::slice::Iter<'a, (SpawnId, Node)>,
1363}
1364
1365impl<'a> Iterator for SpawnedNodes<'a> {
1366    type Item = &'a Node;
1367
1368    fn next(&mut self) -> Option<Self::Item> {
1369        self.iter.next().map(|(_, node)| node)
1370    }
1371}
1372
1373impl DoubleEndedIterator for SpawnedNodes<'_> {
1374    fn next_back(&mut self) -> Option<Self::Item> {
1375        self.iter.next_back().map(|(_, node)| node)
1376    }
1377}