Skip to main content

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