Skip to main content

tui_pages/focus/
target.rs

1/// A focusable element of a page.
2///
3/// `O` is the application-defined overlay type carried by
4/// [`FocusTarget::Overlay`] — your own enum of the modal overlays your TUI has
5/// (a command bar, a search palette, a sidebar, …). The crate provides no
6/// overlay names; you define them. Apps that use no named overlays leave `O`
7/// at its default `()`.
8#[derive(Debug, Clone, PartialEq, Eq, Hash)]
9#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
10pub enum FocusTarget<O = ()> {
11    CanvasField(usize),
12    InternalCanvasField(usize),
13    Button(usize),
14    Section(usize),
15    SectionItem {
16        section: usize,
17        item: usize,
18    },
19    Overlay(O),
20    /// Focus on item `N` inside the currently open modal overlay. The crate
21    /// names no modal kinds: a dialog button, a picker row, or any other
22    /// in-modal item is just a `ModalItem`. The `dialog` feature layers its
23    /// button conventions on top of this.
24    ModalItem(usize),
25    Custom(String),
26}
27
28impl<O> FocusTarget<O> {
29    pub fn is_canvas(&self) -> bool {
30        matches!(
31            self,
32            FocusTarget::CanvasField(_) | FocusTarget::InternalCanvasField(_)
33        )
34    }
35
36    pub fn is_button(&self) -> bool {
37        matches!(self, FocusTarget::Button(_))
38    }
39
40    pub fn is_overlay(&self) -> bool {
41        matches!(self, FocusTarget::Overlay(_) | FocusTarget::ModalItem(_))
42    }
43
44    pub fn is_top_level_navigable(&self) -> bool {
45        !matches!(self, FocusTarget::InternalCanvasField(_))
46    }
47}
48
49impl<O: Clone> FocusTarget<O> {
50    /// The overlay identity if this target is an [`Overlay`](FocusTarget::Overlay).
51    pub fn to_overlay(&self) -> Option<O> {
52        match self {
53            FocusTarget::Overlay(kind) => Some(kind.clone()),
54            _ => None,
55        }
56    }
57}