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 = Colors.tree_foreground 19 var obs selected_foreground = Colors.tree_selected_foreground 20 var obs selected_background = Colors.tree_selected_background 21 var obs unfocused_background = Colors.tree_unfocused_background 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 unfocused_background 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, tree.data.items, 0) 108 Some tree_item -> (tree_item.stack, 109 tree_item.data.items, 110 tree_item.offset + 30) 111 112 let token = items 113 |> Obs.map { item -> 114 let tree_item = TreeItem 115 data = item 116 foreground = tree.foreground 117 =offset 118 119 init_items tree tree_item 120 121 tree_item } 122 123 |> bind { index tree_item -> 124 let data_item = tree_item.data 125 tree.data_tree_items.add data_item tree_item 126 stack.items.add index tree_item } 127 128 { index tree_item -> 129 stack.items.remove_at index 130 let data_item = tree_item.data 131 tree.data_tree_items.remove data_item 132 tree_item.discard } 133 134 case maybe_tree_item of 135 None -> tree.push_token token 136 Some tree_item -> tree_item.push_token token 137 138 type Tree 139 init_items self None 140 141 selected_item@atom.bind { maybe_item -> case maybe_item of 142 None -> if selected_tree_item ? Some tree_item then 143 selected_tree_item = None 144 selected_item = None 145 hide_selection tree_item 146 147 Some item -> 148 let tree_item = data_tree_items[item] 149 select tree_item } |> push_token 150 151 subscribe { _, event -> if event ? FlagEvent/IsFocused x then 152 if selected_tree_item ? Some selected_item then 153 let (f, b) = if x then 154 (selected_foreground, selected_background) 155 else 156 (foreground, unfocused_background) 157 158 selected_item.foreground = f 159 background = b } 160