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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#![allow(dead_code)]
use {
    std::rc::Rc,
    std::cell::RefCell,
    crate::{
        cx_2d::Cx2d,
        makepad_platform::Area,
        makepad_platform::DrawListId,
        makepad_platform::Margin,
        makepad_platform::Cx,
    }
};

#[derive(Default)]
pub struct CxNavTree {
    nav_lists: Vec<CxNavList>
}

#[derive(Clone)]
pub struct CxNavTreeRc(pub Rc<RefCell<CxNavTree >>);

#[derive(Debug, Default, Clone)]
pub struct CxNavList {
    pub nav_list: Vec<NavItem>
}

impl std::ops::Index<DrawListId> for CxNavTree {
    type Output = CxNavList;
    fn index(&self, index: DrawListId) -> &Self::Output {
        &self.nav_lists[index.index()]
    }
}

impl std::ops::IndexMut<DrawListId> for CxNavTree {
    fn index_mut(&mut self, index: DrawListId) -> &mut Self::Output {
        &mut self.nav_lists[index.index()]
    }
}

#[derive(Debug, Clone)]
pub enum NavOrder {
    Default,
    Top(u64),
    Middle(u64),
    Bottom(u64),
}

#[derive(Debug, Clone)]
pub struct NavStop {
    pub role: NavRole,
    pub order: NavOrder,
    pub margin: Margin,
    pub area: Area
}

#[derive(Debug, Clone)]
pub enum NavItem {
    Child(DrawListId),
    Stop(NavStop),
    BeginScroll(Area),
    EndScroll(Area)
}

#[derive(Debug, Clone)]
pub enum NavRole {
    TextInput,
    DropDown,
    Slider,
}

impl<'a> Cx2d<'a> {
    
    pub fn lazy_construct_nav_tree(cx: &mut Cx) {
        // ok lets fetch/instance our CxFontsAtlasRc
        if !cx.has_global::<CxNavTreeRc>() {
            cx.set_global(CxNavTreeRc(Rc::new(RefCell::new(CxNavTree::default()))));
        }
    }
    
    pub fn iterate_nav_stops<F>(cx: &mut Cx, root: DrawListId, mut callback: F) -> Option<(Area, Vec<Area>)> where F: FnMut(&Cx, &NavStop) -> Option<Area> {
        let nav_tree_rc = cx.get_global::<CxNavTreeRc>().clone();
        let nav_tree = &*nav_tree_rc.0.borrow();
        let mut scroll_stack = Vec::new();
        fn iterate_nav_stops<F>(cx: &Cx, scroll_stack: &mut Vec<Area>, nav_tree: &CxNavTree, draw_list_id: DrawListId, callback: &mut F) -> Option<Area> 
        where F: FnMut(&Cx, &NavStop) -> Option<Area> {
            
            for i in 0..nav_tree[draw_list_id].nav_list.len() {
                let nav_item = &nav_tree[draw_list_id].nav_list[i];
                match nav_item {
                    NavItem::Child(draw_list_id) => {
                        if let Some(area) = iterate_nav_stops(cx, scroll_stack, nav_tree, *draw_list_id, callback) {
                            return Some(area)
                        }
                    }
                    NavItem::Stop(stop) => if let Some(area) = callback(cx, stop) {
                        scroll_stack.push(area);
                        return Some(area)
                    }
                    NavItem::BeginScroll(area)=>{
                        scroll_stack.push(*area);
                    }
                    NavItem::EndScroll(area)=>{
                        if *area != scroll_stack.pop().unwrap(){panic!()};
                    }
                }
            }
            None
        }
        if let Some(area) = iterate_nav_stops(cx, &mut scroll_stack, nav_tree, root, &mut callback){
            Some((area, scroll_stack))
        }
        else{
            None
        }
    }
    
    pub fn nav_list_clear(&mut self, draw_list_id: DrawListId) {
        let mut nav_tree = self.nav_tree_rc.0.borrow_mut();
        if draw_list_id.index() >= nav_tree.nav_lists.len() {
            nav_tree.nav_lists.resize(draw_list_id.index() + 1, Default::default());
        }
        nav_tree[draw_list_id].nav_list.clear();
    }
    
    pub fn nav_list_item_push(&mut self, draw_list_id: DrawListId, item: NavItem){
        let mut nav_tree = self.nav_tree_rc.0.borrow_mut();
        nav_tree[draw_list_id].nav_list.push(item);
    }
    
    pub fn add_nav_stop(&mut self, area: Area, role: NavRole, margin: Margin) {
        let draw_list_id = *self.draw_list_stack.last().unwrap();
        self.nav_list_item_push(draw_list_id, NavItem::Stop(NavStop {
            role,
            area,
            order: NavOrder::Default,
            margin
        }));
    }
    
    pub fn add_begin_scroll(&mut self)->NavScrollIndex{
        let mut nav_tree = self.nav_tree_rc.0.borrow_mut();
        let draw_list_id = *self.draw_list_stack.last().unwrap();
        let id = NavScrollIndex(nav_tree[draw_list_id].nav_list.len());
        nav_tree[draw_list_id].nav_list.push(NavItem::BeginScroll(Area::Empty));
        id
    }
    
    pub fn add_end_scroll(&mut self, index:NavScrollIndex, area:Area){
        let mut nav_tree = self.nav_tree_rc.0.borrow_mut();
        let draw_list_id = *self.draw_list_stack.last().unwrap();
        nav_tree[draw_list_id].nav_list[index.0] = NavItem::BeginScroll(area);
        nav_tree[draw_list_id].nav_list.push(NavItem::EndScroll(area));
    }
}

pub struct NavScrollIndex(usize);