verify: implement P_Array_Append_One
[ajla.git] / stdlib / ui / widget / checkbox.ajla
blob2ede415b41df62c9c9f8e32bfe9cc40a3c778ae2
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.checkbox;
21 uses ui.widget.common;
23 type checkbox_state;
25 fn checkbox_init(label : string, color_scheme : bytes, prop : bytes, radio : bool, val : int, w : world, app : appstate, id : wid) : (world, appstate, checkbox_state);
26 fn checkbox_get_width(app : appstate, com : widget_common, st : checkbox_state, x : int) : int;
27 fn checkbox_get_height(app : appstate, com : widget_common, st : checkbox_state, x : int) : int;
28 fn checkbox_reflow(app : appstate, com : widget_common, st : checkbox_state) : (appstate, widget_common, checkbox_state);
29 fn checkbox_redraw(app : appstate, curs : curses, com : widget_common, st : checkbox_state) : curses;
30 fn checkbox_get_cursor(app : appstate, com : widget_common, st : checkbox_state) : (int, int);
31 fn checkbox_accepts_key(app : appstate, com : widget_common, st : checkbox_state, k : event_keyboard) : bool;
32 fn checkbox_process_event(w : world, app : appstate, com : widget_common, st : checkbox_state, wev : wevent) : (world, appstate, widget_common, checkbox_state);
34 const checkbox_class ~flat := widget_class.[
35         t : checkbox_state,
36         name : "checkbox",
37         is_selectable : true,
38         get_width : checkbox_get_width,
39         get_height : checkbox_get_height,
40         reflow : checkbox_reflow,
41         redraw : checkbox_redraw,
42         get_cursor : checkbox_get_cursor,
43         accepts_key : checkbox_accepts_key,
44         process_event : checkbox_process_event,
47 implementation
49 uses ui.widget.text;
51 record checkbox_state [
52         color_scheme : bytes;
53         prop : bytes;
54         radio : bool;
55         val : int;
56         text_id : wid;
59 fn checkbox_init(label : string, color_scheme : bytes, prop : bytes, radio : bool, val : int, implicit w : world, implicit app : appstate, id : wid) : (world, appstate, checkbox_state)
61         property_observe(id, prop);
62         var text_id := widget_new(id, text_class, text_init(widget_align.left, label, color_scheme,,,), false);
63         return checkbox_state.[
64                 color_scheme : color_scheme,
65                 prop : prop,
66                 radio : radio,
67                 val : val,
68                 text_id : text_id,
69         ];
72 fn checkbox_get_width(implicit app : appstate, com : widget_common, st : checkbox_state, x : int) : int
74         return widget_get_width(st.text_id, x - 4) + 4;
77 fn checkbox_get_height(implicit app : appstate, com : widget_common, st : checkbox_state, x : int) : int
79         return widget_get_height(st.text_id, x - 4);
82 fn checkbox_reflow(implicit app : appstate, implicit com : widget_common, implicit st : checkbox_state) : (appstate, widget_common, checkbox_state)
84         var x := checkbox_get_width(com.size_x);
85         com.size_x := min(x, com.size_x);
86         var y := checkbox_get_height(com.size_x);
87         widget_move(st.text_id, 4, 0, com.size_x - 4, y, 0, 0);
90 fn checkbox_is_checked(implicit app : appstate, st : checkbox_state) : bool
92         var prop := property_get(st.prop);
93         if st.radio then
94                 return prop.i = st.val;
95         else
96                 return prop.i bt st.val;
99 fn checkbox_redraw(implicit app : appstate, implicit curs : curses, com : widget_common, implicit st : checkbox_state) : curses
101         property_set_attrib(property_get_attrib(st.color_scheme + "checkbox", #0000, #0000, #0000, #aaaa, #aaaa, #aaaa, 0, curses_invert));
102         curses_fill_rect(0, com.size_x, 0, com.size_y, ' ');
103         curses_set_pos(0, 0);
104         curses_print(select(checkbox_is_checked(), `[ ]`, `[X]`));
105         widget_redraw_subwidgets(com);
108 fn checkbox_get_cursor(app : appstate, com : widget_common, st : checkbox_state) : (int, int)
110         return 1, 0;
113 fn checkbox_accepts_key(app : appstate, com : widget_common, st : checkbox_state, k : event_keyboard) : bool
115         return k.key = ' ';
118 fn checkbox_check(implicit app : appstate, st : checkbox_state) : appstate
120         var new_val : int;
121         if st.radio then [
122                 new_val := st.val;
123         ] else [
124                 new_val := property_get(st.prop).i btc st.val;
125         ]
126         property_set(st.prop, property.i.(new_val));
129 fn checkbox_process_event(implicit w : world, implicit app : appstate, implicit com : widget_common, implicit st : checkbox_state, wev : wevent) : (world, appstate, widget_common, checkbox_state)
131         if wev is keyboard then [
132                 checkbox_check();
133                 return;
134         ]
135         if wev is mouse, wev.mouse.prev_buttons = 1, wev.mouse.buttons = 0 then [
136                 checkbox_check();
137                 return;
138         ]
139         if wev is property_changed then [
140                 goto redraw;
141         ]
142         return;
143 redraw:
144         widget_enqueue_event(com.self, wevent.redraw.(event_redraw.[
145                 x1 : 1,
146                 x2 : 2,
147                 y1 : 0,
148                 y2 : 1,
149         ]));