fold equal records into the same local type
[ajla.git] / stdlib / ui / widget / fkeys.ajla
blobbdb37808449e4d3ce52eb1bb1db24e608c8b6f68
1 {*
2  * Copyright (C) 2024 Mikulas Patocka
3  *
4  * This file is part of Ajla.
5  *
6  * Ajla is free software: you can redistribute it and/or modify it under the
7  * terms of the GNU General Public License as published by the Free Software
8  * Foundation, either version 3 of the License, or (at your option) any later
9  * version.
10  *
11  * Ajla is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * Ajla. If not, see <https://www.gnu.org/licenses/>.
17  *}
19 private unit ui.widget.fkeys;
21 uses ui.widget.common;
23 type fkeys_state;
25 fn fkeys_init(n_keys : int, color_scheme : bytes, w : world, app : appstate, id : wid) : (world, appstate, fkeys_state);
26 fn fkeys_redraw(app : appstate, curs : curses, com : widget_common, st : fkeys_state) : curses;
27 fn fkeys_process_event(w : world, app : appstate, com : widget_common, st : fkeys_state, wev : wevent) : (world, appstate, widget_common, fkeys_state);
29 const fkeys_class~flat := widget_class.[
30         t : fkeys_state,
31         name : "fkeys",
32         is_selectable : false,
33         redraw : fkeys_redraw,
34         process_event : fkeys_process_event,
37 implementation
39 record fkeys_state [
40         labels : list(string);
41         lengths : list(int);
42         color_scheme : bytes;
45 fn fkeys_load(implicit app : appstate, implicit st : fkeys_state) : fkeys_state
47         var p := property_get("fkeys");
48         if p is l then [
49                 for i := 0 to len(st.labels) do [
50                         if i < len(p.l) then
51                                 st.labels[i] := p.l[i].s;
52                         else
53                                 st.labels[i] := ``;
54                 ]
55         ]
58 fn fkeys_init(n_keys : int, color_scheme : bytes, implicit w : world, implicit app : appstate, id : wid) : (world, appstate, fkeys_state)
60         property_observe(id, "fkeys");
61         implicit st := fkeys_state.[
62                 labels : fill(``, n_keys),
63                 lengths : fill(0, n_keys),
64                 color_scheme : color_scheme,
65         ];
66         fkeys_load();
69 fn fkeys_reflow(implicit app : appstate, implicit com : widget_common, implicit st : fkeys_state) : (appstate, widget_common, fkeys_state)
71         var num_size := 0;
72         for i := 0 to len(st.labels) do [
73                 if i <> 0 then
74                         num_size += 1;
75                 num_size += len(ntos(i + 1));
76         ]
77         var label_size := max(com.size_x - num_size, 0);
78         for i := 0 to len(st.labels) do [
79                 st.lengths[i] := label_size div len(st.labels) + select(i < label_size mod len(st.labels), 0, 1);
80         ]
84 fn fkeys_redraw(implicit app : appstate, implicit curs : curses, com : widget_common, st : fkeys_state) : curses
86         var pn := property_get_attrib(st.color_scheme + "fkeys-number", #aaaa, #aaaa, #aaaa, #0000, #0000, #0000, 0, 0);
87         var pt := property_get_attrib(st.color_scheme + "fkeys-text", #0000, #0000, #0000, #aaaa, #aaaa, #aaaa, 0, curses_invert);
88         curses_set_pos(0, 0);
89         for i := 0 to len(st.labels) do [
90                 property_set_attrib(pn);
91                 if i <> 0 then
92                         curses_print(` `);
93                 curses_print(utf8_to_string(ntos(i + 1)));
94                 property_set_attrib(pt);
95                 var s := st.labels[i];
96                 var l := st.lengths[i];
97                 s := list_right_pad(s, l, ' ')[ .. l];
98                 curses_print(s);
99         ]
102 fn fkeys_process_event(implicit w : world, implicit app : appstate, implicit com : widget_common, implicit st : fkeys_state, wev : wevent) : (world, appstate, widget_common, fkeys_state)
104         if wev is resize then [
105                 com.x := 0;
106                 com.size_x := wev.resize.x;
107                 com.y := wev.resize.y - 1;
108                 com.size_y := 1;
109                 fkeys_reflow();
110                 goto redraw;
111         ]
112         if wev is property_changed then [
113                 fkeys_load();
114                 goto redraw;
115         ]
116         if wev is keyboard then [
117                 widget_enqueue_event_to_underlying(com.self, wev);
118                 return;
119         ]
120         if wev is mouse then [
121                 var clicked : int;
122                 var mx, my := widget_relative_mouse_coords(com.self, wev.mouse);
123                 if (wev.mouse.prev_buttons and not wev.mouse.buttons) <> 0, my = 0 then [
124                         for i := 0 to len(st.labels) do [
125                                 var this_len := 0;
126                                 if i <> 0 then [
127                                         this_len := 1;
128                                         if mx = 0 then
129                                                 break;
130                                 ]
131                                 this_len += len(ntos(i + 1));
132                                 this_len += st.lengths[i];
133                                 if mx < this_len then [
134                                         clicked := i;
135                                         goto clicked;
136                                 ]
137                                 mx -= this_len;
138                         ]
139                 ]
140                 widget_enqueue_event_to_underlying(com.self, wev);
141                 return;
142 clicked:
143                 var wev_f := wevent.keyboard.(event_keyboard.[
144                         key : key_f1 - clicked,
145                         flags : 0,
146                         rep : 1,
147                 ]);
148                 widget_enqueue_event_to_underlying(com.self, wev_f);
149                 return;
150         ]
151         return;
153 redraw:
154         widget_enqueue_event(com.self, wevent.redraw.(event_redraw.[
155                 x1 : 0,
156                 x2 : com.size_x,
157                 y1 : 0,
158                 y2 : com.size_y,
159         ]));