1     type TreeDataItem @abstract @mut =
2         var obs name = ""
3         var obs is_open = false
4         val items : obs/List<TreeDataItem>
5     
6     type TreeItem =
7         inherit Wrapper
8     
9         var obs foreground = Vector3.new
10        var obs background = Vector3.new
11        var obs is_selected = false
12        var obs offset : u32 = 0
13        val data : TreeDataItem
14    
15    type Tree @mut =
16        inherit Wrapper
17    
18        var obs foreground = Vector3.color "333333"
19        var obs selected_foreground = Vector3.color "DDDDDD"
20        var obs selected_background = Vector3.color "444444"
21        var obs selected_background_unfocused = Vector3.color "AFAFAF"
22        var obs selected_item : Option<TreeDataItem> = None
23        var obs selected_tree_item : Option<TreeItem> @[mut private] = None
24    
25        val data : TreeDataItem
26        let data_tree_items = Map<TreeDataItem, TreeItem>.new
27        val on_open @[mut private] = Stream<TreeDataItem>.new
28    
29        let stack = Stack.new
30        content = stack
31    
32        is_focusable = true
33    
34        let hide_selection (tree_item : TreeItem) =
35            tree_item.foreground = foreground
36                      is_selected = false
37    
38        def select (tree_item : TreeItem) =
39            let maybe_prev_item = selected_tree_item
40            if maybe_prev_item <> Some tree_item then
41                selected_item = tree_item.data
42                selected_tree_item = Some tree_item
43    
44                let is_focused_or_not_tree = is_focused
45                let set_foreground = is_focused_or_not_tree
46                if is_focused then
47                    tree_item.foreground = selected_foreground
48    
49                tree_item.is_selected = true
50                          background = if is_focused
51                                       then selected_background
52                                       else selected_background_unfocused
53    
54                if maybe_prev_item ? Some prev_item then
55                    hide_selection prev_item
56    
57    type TreeItem
58        val margin = Margin.new
59        let text_box = TextBox.new
60        let stack = Stack.new
61        let rectangle = Rectangle.new
62    
63        is_selected@atom.bind { rectangle.is_visible = _ }
64        |> push_token
65    
66        data.is_open@atom.bind { stack.is_visible = _ }
67        |> push_token
68    
69        is_clickable = true
70    
71        let splitter = Splitter
72            ratio = 0
73            is_vertical = true
74            Aligner
75                rectangle
76                    color@obs = background@obs
77                margin
78                    left@obs = offset@obs
79                    align_h = AlignH/Left
80                    is_clickable = true
81                    TextBlock
82                        text@obs = data.name@obs
83                        color@obs = foreground@obs
84                text_box
85                    is_visible = false
86            stack
87    
88        content = splitter
89    
90        def edit =
91            text_box.text = data.name
92            margin.is_visible = false
93            text_box.is_visible = true
94            text_box
95    
96        margin.subscribe { _, event -> if event.is_mouse_press then
97            let tree = find_parent self { _ is Tree } as Tree
98            tree.selected_item = data
99            tree.on_open.push data }
100   
101       subscribe { _, event -> if event.is_mouse_press then
102           let tree = find_parent self { _ is Tree } as Tree
103           tree.select self }
104   
105   let init_items (tree : Tree) (maybe_tree_item : Option<TreeItem>) : Unit =
106       let (stack, items, offset) = case maybe_tree_item of
107           None -> (tree.stack
108                    tree.data.items
109                    0)
110   
111           Some tree_item -> (tree_item.stack
112                              tree_item.data.items
113                              tree_item.offset + 30)
114   
115       let token = items
116           |> Obs.map { item ->
117               let tree_item = TreeItem
118                   data = item
119                   foreground = tree.foreground
120                   =offset
121   
122               init_items tree tree_item
123   
124               tree_item }
125   
126           |> bind { index tree_item ->
127                         let data_item = tree_item.data
128                         tree.data_tree_items.add data_item tree_item
129                         stack.items.add index tree_item }
130   
131                   { index tree_item ->
132                         stack.items.remove_at index
133                         let data_item = tree_item.data
134                         tree.data_tree_items.remove data_item
135                         tree_item.discard }
136   
137       case maybe_tree_item of
138           None -> tree.push_token token
139           Some tree_item -> tree_item.push_token token
140   
141   type Tree
142       init_items self None
143   
144       selected_item@atom.bind { maybe_item -> case maybe_item of
145           None -> if selected_tree_item ? Some tree_item then
146               selected_tree_item = None
147               selected_item = None
148               hide_selection tree_item
149   
150           Some item ->
151               let tree_item = data_tree_items[item]
152               select tree_item } |> push_token
153   
154       subscribe { _, event -> if event ? FlagEvent/IsFocused x then
155           if selected_tree_item ? Some selected_item then
156               let (f, b) = if x then
157                   (selected_foreground, selected_background)
158               else
159                   (foreground, selected_background_unfocused)
160   
161               selected_item.foreground = f
162                             background = b }
163