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