source: mainline/uspace/lib/ui/test/tabset.c

Last change on this file was 1eaead4, checked in by Jiri Svoboda <jiri@…>, 2 years ago

Tab set control

This allows to expand the space available in a dialog window
using stacking, with individual tabs that can be activated
by clicking the handle.

  • Property mode set to 100644
File size: 8.7 KB
Line 
1/*
2 * Copyright (c) 2023 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <gfx/coord.h>
30#include <mem.h>
31#include <pcut/pcut.h>
32#include <stdbool.h>
33#include <ui/control.h>
34#include <ui/tab.h>
35#include <ui/tabset.h>
36#include <ui/testctl.h>
37#include <ui/ui.h>
38#include <ui/window.h>
39#include "../private/tabset.h"
40
41PCUT_INIT;
42
43PCUT_TEST_SUITE(tabset);
44
45/** Create and destroy tab set */
46PCUT_TEST(create_destroy)
47{
48 ui_tab_set_t *tabset = NULL;
49 errno_t rc;
50
51 rc = ui_tab_set_create(NULL, &tabset);
52 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
53 PCUT_ASSERT_NOT_NULL(tabset);
54
55 ui_tab_set_destroy(tabset);
56}
57
58/** ui_tab_set_destroy() can take NULL argument (no-op) */
59PCUT_TEST(destroy_null)
60{
61 ui_tab_set_destroy(NULL);
62}
63
64/** ui_tab_set_ctl() returns control that has a working virtual destructor */
65PCUT_TEST(ctl)
66{
67 ui_tab_set_t *tabset = NULL;
68 ui_control_t *control;
69 errno_t rc;
70
71 rc = ui_tab_set_create(NULL, &tabset);
72 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
73 PCUT_ASSERT_NOT_NULL(tabset);
74
75 control = ui_tab_set_ctl(tabset);
76 PCUT_ASSERT_NOT_NULL(control);
77
78 ui_control_destroy(control);
79}
80
81/** Set tab set rectangle sets internal field */
82PCUT_TEST(set_rect)
83{
84 errno_t rc;
85 ui_t *ui = NULL;
86 ui_window_t *window = NULL;
87 ui_wnd_params_t params;
88 ui_resource_t *res;
89 ui_tab_set_t *tabset = NULL;
90 gfx_rect_t rect;
91
92 rc = ui_create_disp(NULL, &ui);
93 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
94
95 ui_wnd_params_init(&params);
96 params.caption = "Hello";
97
98 rc = ui_window_create(ui, &params, &window);
99 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
100 PCUT_ASSERT_NOT_NULL(window);
101
102 res = ui_window_get_res(window);
103
104 rc = ui_tab_set_create(res, &tabset);
105 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
106 PCUT_ASSERT_NOT_NULL(tabset);
107
108 rect.p0.x = 1;
109 rect.p0.y = 2;
110 rect.p1.x = 3;
111 rect.p1.y = 4;
112
113 ui_tab_set_set_rect(tabset, &rect);
114 PCUT_ASSERT_INT_EQUALS(rect.p0.x, tabset->rect.p0.x);
115 PCUT_ASSERT_INT_EQUALS(rect.p0.y, tabset->rect.p0.y);
116 PCUT_ASSERT_INT_EQUALS(rect.p1.x, tabset->rect.p1.x);
117 PCUT_ASSERT_INT_EQUALS(rect.p1.y, tabset->rect.p1.y);
118
119 ui_tab_set_destroy(tabset);
120 ui_window_destroy(window);
121 ui_destroy(ui);
122}
123
124/** Paint tab set */
125PCUT_TEST(paint)
126{
127 ui_t *ui = NULL;
128 ui_window_t *window = NULL;
129 ui_wnd_params_t params;
130 ui_resource_t *res;
131 ui_tab_set_t *tabset = NULL;
132 errno_t rc;
133
134 rc = ui_create_disp(NULL, &ui);
135 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
136
137 ui_wnd_params_init(&params);
138 params.caption = "Hello";
139
140 rc = ui_window_create(ui, &params, &window);
141 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
142 PCUT_ASSERT_NOT_NULL(window);
143
144 res = ui_window_get_res(window);
145
146 rc = ui_tab_set_create(res, &tabset);
147 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
148 PCUT_ASSERT_NOT_NULL(tabset);
149
150 rc = ui_tab_set_paint(tabset);
151 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
152
153 ui_tab_set_destroy(tabset);
154 ui_window_destroy(window);
155 ui_destroy(ui);
156}
157
158/** Deliver tab set keyboard event */
159PCUT_TEST(kbd_event)
160{
161 ui_t *ui = NULL;
162 ui_window_t *window = NULL;
163 ui_wnd_params_t params;
164 ui_resource_t *res;
165 ui_tab_set_t *tabset = NULL;
166 ui_tab_t *tab = NULL;
167 ui_evclaim_t claimed;
168 kbd_event_t event;
169 ui_test_ctl_t *testctl = NULL;
170 ui_tc_resp_t resp;
171 errno_t rc;
172
173 rc = ui_create_disp(NULL, &ui);
174 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
175
176 ui_wnd_params_init(&params);
177 params.caption = "Hello";
178
179 rc = ui_window_create(ui, &params, &window);
180 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
181 PCUT_ASSERT_NOT_NULL(window);
182
183 res = ui_window_get_res(window);
184
185 rc = ui_tab_set_create(res, &tabset);
186 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
187 PCUT_ASSERT_NOT_NULL(tabset);
188
189 /* Without anytabs, event should be unclaimed */
190 event.type = KEY_PRESS;
191 event.key = KC_ENTER;
192 event.mods = 0;
193 claimed = ui_tab_set_kbd_event(tabset, &event);
194 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
195 PCUT_ASSERT_EQUALS(ui_unclaimed, claimed);
196
197 rc = ui_tab_create(tabset, "Test", &tab);
198 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
199 PCUT_ASSERT_NOT_NULL(tab);
200
201 rc = ui_test_ctl_create(&resp, &testctl);
202 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
203
204 /* Set up response */
205 ui_tab_add(tab, ui_test_ctl_ctl(testctl));
206 resp.claim = ui_claimed;
207 resp.kbd = false;
208
209 /* Send keyboard event */
210 event.type = KEY_PRESS;
211 event.key = KC_F10;
212 event.mods = 0;
213 claimed = ui_tab_set_kbd_event(tabset, &event);
214 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
215 PCUT_ASSERT_EQUALS(ui_claimed, claimed);
216
217 /* Make sure event was delivered */
218 PCUT_ASSERT_TRUE(resp.kbd);
219 PCUT_ASSERT_EQUALS(event.type, resp.kevent.type);
220 PCUT_ASSERT_EQUALS(event.key, resp.kevent.key);
221 PCUT_ASSERT_EQUALS(event.mods, resp.kevent.mods);
222
223 ui_tab_set_destroy(tabset);
224 ui_window_destroy(window);
225 ui_destroy(ui);
226}
227
228/** Press event on tab handle selects tab */
229PCUT_TEST(pos_event_select)
230{
231 ui_t *ui = NULL;
232 ui_window_t *window = NULL;
233 ui_wnd_params_t params;
234 ui_resource_t *res;
235 ui_tab_set_t *tabset = NULL;
236 ui_tab_t *tab1 = NULL;
237 ui_tab_t *tab2 = NULL;
238 ui_evclaim_t claimed;
239 pos_event_t event;
240 errno_t rc;
241
242 rc = ui_create_disp(NULL, &ui);
243 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
244
245 ui_wnd_params_init(&params);
246 params.caption = "Hello";
247
248 rc = ui_window_create(ui, &params, &window);
249 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
250 PCUT_ASSERT_NOT_NULL(window);
251
252 res = ui_window_get_res(window);
253
254 rc = ui_tab_set_create(res, &tabset);
255 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
256 PCUT_ASSERT_NOT_NULL(tabset);
257
258 /* Without any tabs, event should be unclaimed */
259 event.type = POS_PRESS;
260 event.hpos = 80;
261 event.vpos = 4;
262 event.btn_num = 1;
263 claimed = ui_tab_set_pos_event(tabset, &event);
264 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
265 PCUT_ASSERT_EQUALS(ui_unclaimed, claimed);
266
267 rc = ui_tab_create(tabset, "Test 1", &tab1);
268 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
269
270 /* The first added tab should be automatically selected */
271 PCUT_ASSERT_EQUALS(tab1, tabset->selected);
272
273 rc = ui_tab_create(tabset, "Test 2", &tab2);
274 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
275
276 /* After adding a second tab the first should still be selected */
277 PCUT_ASSERT_EQUALS(tab1, tabset->selected);
278
279 event.type = POS_PRESS;
280 event.hpos = 80;
281 event.vpos = 4;
282 event.btn_num = 1;
283 claimed = ui_tab_set_pos_event(tabset, &event);
284 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
285 PCUT_ASSERT_EQUALS(ui_claimed, claimed);
286
287 /* Clicking the second tab handle should select tab2 */
288 PCUT_ASSERT_EQUALS(tab2, tabset->selected);
289
290 ui_tab_set_destroy(tabset);
291 ui_window_destroy(window);
292 ui_destroy(ui);
293}
294
295/** ui_tab_set_select() selects tab */
296PCUT_TEST(select)
297{
298 ui_t *ui = NULL;
299 ui_window_t *window = NULL;
300 ui_wnd_params_t params;
301 ui_resource_t *res;
302 ui_tab_set_t *tabset = NULL;
303 ui_tab_t *tab1 = NULL;
304 ui_tab_t *tab2 = NULL;
305 errno_t rc;
306
307 rc = ui_create_disp(NULL, &ui);
308 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
309
310 ui_wnd_params_init(&params);
311 params.caption = "Hello";
312
313 rc = ui_window_create(ui, &params, &window);
314 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
315 PCUT_ASSERT_NOT_NULL(window);
316
317 res = ui_window_get_res(window);
318
319 rc = ui_tab_set_create(res, &tabset);
320 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
321 PCUT_ASSERT_NOT_NULL(tabset);
322
323 rc = ui_tab_create(tabset, "Test 1", &tab1);
324 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
325
326 /* The first added tab should be automatically selected */
327 PCUT_ASSERT_EQUALS(tab1, tabset->selected);
328
329 rc = ui_tab_create(tabset, "Test 2", &tab2);
330 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
331
332 /* After adding a second tab the first should still be selected */
333 PCUT_ASSERT_EQUALS(tab1, tabset->selected);
334
335 /* Select second tab */
336 ui_tab_set_select(tabset, tab2);
337
338 /* Now the second tab should be selected */
339 PCUT_ASSERT_EQUALS(tab2, tabset->selected);
340
341 ui_tab_set_destroy(tabset);
342 ui_window_destroy(window);
343 ui_destroy(ui);
344}
345
346PCUT_EXPORT(tabset);
Note: See TracBrowser for help on using the repository browser.