1    local text_position_to_y (text_display : TextDisplay) (position : TextPos) =
2        let up = position.line * text_display.font.line_height
3        let down = up + text_display.font.line_height + text_display.margin.up
4        (up, down)
5    
6    type MultilineTextBox
7        let selection_color = Colors.multiline_text_box_selection
8        local (selection_start, selection_middle, selection_end) =
9            let args = (color = selection_color,
10                       is_visible = false)
11   
12           (Rectangle f@ args,
13            Rectangle f@ args,
14            Rectangle f@ args)
15   
16       val text_display = TextDisplay font
17                                      margin = text_margin
18                                      offset_y = selection_offset_y
19       val numbers_display = TextDisplay font
20                                         margin = text_margin
21                                         should_align = true
22       val scroller = Scroller.new
23       let numbers_border = Border.new
24       local scissor_control = ScissorControl.new
25   
26       local canvas = Canvas
27           exclude_width <- selection_start
28                            selection_middle
29                            selection_end
30                            text_display
31   
32       show_line_numbers@atom.bind { numbers_border.is_visible = _ }
33       |> push_token
34   
35       let rectangle = Rectangle
36           color@obs = background@obs
37           scroller
38               Splitter
39                   ratio = 0
40                   numbers_border
41                       right = 1
42                       color = Colors.multiline_text_box_numbers_border
43                       Rectangle
44                           color = Colors.multiline_text_box_numbers_background
45                           Margin
46                               right = 24
47                               numbers_display
48                   scissor_control
49                       canvas
50                           selection_start
51                           selection_middle
52                           selection_end
53                           text_display
54   
55       content = rectangle
56       offset_controls.add text_display
57                       add selection_start
58                       add selection_middle
59                       add selection_end
60   
61       def update_colors (from : u32) (to : u32) =
62           if update_colors ? Some f then
63               f display_text from to
64   
65       def update_colors (index : u32) =
66           update_colors index index
67   
68       def show self (position : TextPos) =
69           let scroller = self.scroller
70   
71           let scroll_to (y : u32) =
72               scroller/move_to scroller None -y.as<i32>
73   
74           let font = self.font
75           let (up, down) = text_position_to_y self.text_display position
76           if scroller.visible_y.down - font.line_height < down then
77               let y = down + font.line_height
78                       + scroller.visible_y.up - scroller.visible_y.down
79   
80               scroll_to y
81   
82           else if scroller.visible_y.up + font.line_height > up then
83               let y = if up > font.line_height
84                       then up - font.line_height
85                       else 0
86   
87               scroll_to y
88