1     type Splitter @mut =
2         inherit Panel
3     
4         var ratio : f32 = 0
5         var is_vertical = false
6     
7         let mut first : Option<Control> = None
8         let mut second : Option<Control> = None
9     
10        let update () =
11            first = if items.size > 0 then Some items[0] else None
12            second = if items.size > 1 then Some items[1] else None
13    
14        items |> Obs.subscribe { update } |> push_token
15    
16        def Control.measure self w h =
17            let maybe_first = self.first.filter { _.is_visible }
18            let maybe_second = self.second.filter { _.is_visible }
19            let ratio = self.ratio
20            let is_vertical = self.is_vertical
21    
22            let (res_w, res_h) = case (maybe_first, maybe_second) of
23                None, None -> (0, 0)
24                Some first, None ->
25                    measure_clamped first w h
26                    (first.measure_width, first.measure_height)
27    
28                None, Some second ->
29                    measure_clamped second w h
30                    (second.measure_width, second.measure_height)
31    
32                Some first, Some second ->
33                    if ratio == 0 || ratio == 1 then
34                        if ratio == 0 then
35                            measure_clamped first w h
36    
37                            if is_vertical then
38                                measure_clamped second w (h - first.measure_height)
39                            else
40                                let max_w = if w == 0 then 0 else w - first.measure_width
41                                measure_clamped second max_w h
42                        else
43                            assert ratio == 1
44                            measure_clamped second w h
45    
46                            if is_vertical then
47                                measure_clamped first w (h - second.measure_height)
48                            else
49                                let max_w = if w == 0 then 0 else w - second.measure_width
50                                measure_clamped first max_w h
51    
52                        if is_vertical then
53                            (first.measure_width.max second.measure_width
54                             first.measure_height + second.measure_height)
55                        else
56                            (first.measure_width + second.measure_width
57                             first.measure_height.max second.measure_height)
58                    else
59                        if is_vertical then
60                            let first_h = h as f32 * ratio |> round as u32
61                            let second_h = h - first_h
62                            measure_clamped first w first_h
63                            measure_clamped second w second_h
64    
65                            let res_w = first.measure_width.max second.measure_width
66                            let res_h = first.measure_height as f32 / ratio
67                                |> max (second.measure_height as f32 / (1 - ratio))
68                                |> round as u32
69    
70                            (res_w, res_h)
71                        else
72                            let first_w = w as f32 * ratio |> round as u32
73                            let second_w = w - first_w
74                            measure_clamped first first_w h
75                            measure_clamped second second_w h
76    
77                            let res_w = first.measure_width as f32 / ratio
78                                |> max (second.measure_width as f32 / (1 - ratio))
79                                |> round as u32
80    
81                            let res_h = first.measure_height.max second.measure_height
82                            (res_w, res_h)
83    
84            self.measure_width = res_w
85                 measure_height = res_h
86    
87        def Control.arrange self =
88            let ratio = self.ratio
89            let is_vertical = self.is_vertical
90            let splitter_width = self.width
91            let splitter_height = self.height
92    
93            let maybe_first = self.first.filter { _.is_visible }
94            let maybe_second = self.second.filter { _.is_visible }
95    
96            let first_measure_value = maybe_first
97                |> map { x -> if is_vertical
98                              then x.measure_height
99                              else x.measure_width }
100               |> unwrap_or 0
101   
102           let second_measure_value = maybe_second
103               |> map { x -> if is_vertical
104                             then x.measure_height
105                             else x.measure_width }
106               |> unwrap_or 0
107   
108           let splitter_value = if is_vertical
109                                then splitter_height
110                                else splitter_width
111   
112           let first_value = case ratio of
113               0 -> first_measure_value
114               1 -> splitter_value - second_measure_value
115               else -> splitter_value as f32 * ratio |> round as u32
116   
117           let second_value = case ratio of
118               1 -> second_measure_value
119               0 -> splitter_value - first_value
120               else -> splitter_value as f32 * (1 - ratio) |> round as u32
121   
122           let f (control : Control) (offset : u32) (max_value : u32) =
123               let (offset_x, offset_y) = if is_vertical
124                                          then (0, offset)
125                                          else (offset, 0)
126   
127               let max_control_width = if is_vertical
128                                       then splitter_width
129                                       else max_value
130   
131               let max_control_height = if is_vertical
132                                        then max_value
133                                        else splitter_height
134               do
135                   let width = if control.align_h == AlignH/Stretch
136                               then max_control_width
137                               else control.measure_width.min max_control_width
138   
139                   let height = if control.align_v == AlignV/Stretch
140                                then max_control_height
141                                else control.measure_height.min max_control_height
142   
143                   control.width = width
144                           height = height
145   
146                   assert control.width <= max_control_width
147                   control.arrange
148   
149               let width = control.width
150               let height = control.height
151   
152               let x = case control.align_h of
153                           AlignH/Left | AlignH/Stretch -> 0
154                           AlignH/Right -> max_control_width - width
155                           AlignH/Center -> (max_control_width - width) / 2
156                       + offset_x
157   
158               let y = case control.align_v of
159                           AlignV/Up | AlignV/Stretch -> 0
160                           AlignV/Down -> max_control_height - height
161                           AlignV/Center -> (max_control_height.max height - height) / 2
162                       + offset_y
163   
164               control.position = Vector3 x.as<f32> y.as<f32> Control.offset_z
165   
166           if maybe_first ? Some first then
167               f first 0 first_value
168   
169           if maybe_second ? Some second then
170               f second first_value second_value
171