vizia_core/tree/
focus_iter.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
use crate::entity::Entity;
use crate::prelude::Style;
use crate::style::{Abilities, Display};
use vizia_id::GenerationalId;
use vizia_storage::{
    DoubleEndedTreeTour, FocusTreeIterator, TourDirection, Tree, TreeExt, TreeTour,
};

/// Should the user be able to navigate to the entity with tab?
pub(crate) fn is_navigatable(
    tree: &Tree<Entity>,
    style: &Style,
    node: Entity,
    lock_focus_to: Entity,
) -> bool {
    // Skip invisible widgets
    // if cx.cache.get_visibility(node) == Visibility::Hidden {
    //     return false;
    // }

    // Skip disabled widgets
    if style.disabled.get(node).cloned().unwrap_or_default() {
        return false;
    }

    // Skip non-displayed widgets
    if style.display.get(node).copied().unwrap_or_default() == Display::None {
        return false;
    }

    // Skip nodes outside of the subtree
    if !node.is_descendant_of(tree, lock_focus_to) {
        return false;
    }

    // Skip ignored widgets
    if tree.is_ignored(node) {
        return false;
    }

    style
        .abilities
        .get(node)
        .map(|abilities| abilities.contains(Abilities::NAVIGABLE))
        .unwrap_or(false)
}

/// Get the next entity to be focused during forward keyboard navigation.
pub(crate) fn focus_forward(
    tree: &Tree<Entity>,
    style: &Style,
    node: Entity,
    lock_focus_to: Entity,
) -> Option<Entity> {
    FocusTreeIterator::new(
        tree,
        DoubleEndedTreeTour::new(Some(node), Some(Entity::root())),
        |node| {
            style.display.get(node).copied().unwrap_or_default() == Display::None
            // false
        },
    )
    .skip(1)
    .find(|node| is_navigatable(tree, style, *node, lock_focus_to))
}

/// Get the next entity to be focused during backward keybaord navigation.
pub(crate) fn focus_backward(
    tree: &Tree<Entity>,
    style: &Style,
    node: Entity,
    lock_focus_to: Entity,
) -> Option<Entity> {
    let mut iter = FocusTreeIterator::new(
        tree,
        DoubleEndedTreeTour::new_raw(
            TreeTour::new(Some(Entity::root())),
            TreeTour::with_direction(Some(node), TourDirection::Leaving),
        ),
        |node| {
            // Check if any ancestors are not displayed.
            // TODO: Think of a better way to do thus.
            for ancestor in node.parent_iter(tree) {
                if style.display.get(ancestor).copied().unwrap_or_default() == Display::None {
                    return true;
                }
            }

            false
        },
    );
    iter.next_back();
    iter.filter(|node| is_navigatable(tree, style, *node, lock_focus_to)).next_back()
}