source: mainline/uspace/lib/ui/test/pbutton.c@ b41564c

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b41564c was 3583ffb, checked in by Jiri Svoboda <jiri@…>, 5 years ago

Revert "Create UI controls based on UI object…"

This was a mistake. Controls need ui_resource object, which must be
(at least currently) specific to a window and cannot be obtained from
ui_t.

  • Property mode set to 100644
File size: 13.9 KB
Line 
1/*
2 * Copyright (c) 2020 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/context.h>
30#include <gfx/coord.h>
31#include <mem.h>
32#include <pcut/pcut.h>
33#include <stdbool.h>
34#include <ui/control.h>
35#include <ui/pbutton.h>
36#include <ui/resource.h>
37#include "../private/pbutton.h"
38
39PCUT_INIT;
40
41PCUT_TEST_SUITE(pbutton);
42
43static errno_t testgc_set_color(void *, gfx_color_t *);
44static errno_t testgc_fill_rect(void *, gfx_rect_t *);
45static errno_t testgc_bitmap_create(void *, gfx_bitmap_params_t *,
46 gfx_bitmap_alloc_t *, void **);
47static errno_t testgc_bitmap_destroy(void *);
48static errno_t testgc_bitmap_render(void *, gfx_rect_t *, gfx_coord2_t *);
49static errno_t testgc_bitmap_get_alloc(void *, gfx_bitmap_alloc_t *);
50
51static gfx_context_ops_t ops = {
52 .set_color = testgc_set_color,
53 .fill_rect = testgc_fill_rect,
54 .bitmap_create = testgc_bitmap_create,
55 .bitmap_destroy = testgc_bitmap_destroy,
56 .bitmap_render = testgc_bitmap_render,
57 .bitmap_get_alloc = testgc_bitmap_get_alloc
58};
59
60static void test_pbutton_clicked(ui_pbutton_t *, void *);
61
62static ui_pbutton_cb_t test_pbutton_cb = {
63 .clicked = test_pbutton_clicked
64};
65
66static ui_pbutton_cb_t dummy_pbutton_cb = {
67};
68
69typedef struct {
70 bool bm_created;
71 bool bm_destroyed;
72 gfx_bitmap_params_t bm_params;
73 void *bm_pixels;
74 gfx_rect_t bm_srect;
75 gfx_coord2_t bm_offs;
76 bool bm_rendered;
77 bool bm_got_alloc;
78} test_gc_t;
79
80typedef struct {
81 test_gc_t *tgc;
82 gfx_bitmap_alloc_t alloc;
83 bool myalloc;
84} testgc_bitmap_t;
85
86typedef struct {
87 bool clicked;
88} test_cb_resp_t;
89
90/** Create and destroy button */
91PCUT_TEST(create_destroy)
92{
93 ui_pbutton_t *pbutton = NULL;
94 errno_t rc;
95
96 rc = ui_pbutton_create(NULL, "Hello", &pbutton);
97 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
98 PCUT_ASSERT_NOT_NULL(pbutton);
99
100 ui_pbutton_destroy(pbutton);
101}
102
103/** ui_pbutton_destroy() can take NULL argument (no-op) */
104PCUT_TEST(destroy_null)
105{
106 ui_pbutton_destroy(NULL);
107}
108
109/** ui_pbutton_ctl() returns control that has a working virtual destructor */
110PCUT_TEST(ctl)
111{
112 ui_pbutton_t *pbutton;
113 ui_control_t *control;
114 errno_t rc;
115
116 rc = ui_pbutton_create(NULL, "Hello", &pbutton);
117 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
118
119 control = ui_pbutton_ctl(pbutton);
120 PCUT_ASSERT_NOT_NULL(control);
121
122 ui_control_destroy(control);
123}
124
125/** Set button rectangle sets internal field */
126PCUT_TEST(set_rect)
127{
128 ui_pbutton_t *pbutton;
129 gfx_rect_t rect;
130 errno_t rc;
131
132 rc = ui_pbutton_create(NULL, "Hello", &pbutton);
133 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
134
135 rect.p0.x = 1;
136 rect.p0.y = 2;
137 rect.p1.x = 3;
138 rect.p1.y = 4;
139
140 ui_pbutton_set_rect(pbutton, &rect);
141 PCUT_ASSERT_INT_EQUALS(rect.p0.x, pbutton->rect.p0.x);
142 PCUT_ASSERT_INT_EQUALS(rect.p0.y, pbutton->rect.p0.y);
143 PCUT_ASSERT_INT_EQUALS(rect.p1.x, pbutton->rect.p1.x);
144 PCUT_ASSERT_INT_EQUALS(rect.p1.y, pbutton->rect.p1.y);
145
146 ui_pbutton_destroy(pbutton);
147}
148
149/** Set default flag sets internal field */
150PCUT_TEST(set_default)
151{
152 ui_pbutton_t *pbutton;
153 errno_t rc;
154
155 rc = ui_pbutton_create(NULL, "Hello", &pbutton);
156 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
157
158 ui_pbutton_set_default(pbutton, true);
159 PCUT_ASSERT_TRUE(pbutton->isdefault);
160
161 ui_pbutton_set_default(pbutton, false);
162 PCUT_ASSERT_FALSE(pbutton->isdefault);
163
164 ui_pbutton_destroy(pbutton);
165}
166
167/** Paint button */
168PCUT_TEST(paint)
169{
170 errno_t rc;
171 gfx_context_t *gc = NULL;
172 test_gc_t tgc;
173 ui_resource_t *resource = NULL;
174 ui_pbutton_t *pbutton;
175
176 memset(&tgc, 0, sizeof(tgc));
177 rc = gfx_context_new(&ops, &tgc, &gc);
178 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
179
180 rc = ui_resource_create(gc, &resource);
181 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
182 PCUT_ASSERT_NOT_NULL(resource);
183
184 rc = ui_pbutton_create(resource, "Hello", &pbutton);
185 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
186
187 rc = ui_pbutton_paint(pbutton);
188 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
189
190 ui_pbutton_destroy(pbutton);
191 ui_resource_destroy(resource);
192
193 rc = gfx_context_delete(gc);
194 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
195}
196
197/** Test ui_pbutton_clicked() */
198PCUT_TEST(clicked)
199{
200 errno_t rc;
201 ui_pbutton_t *pbutton;
202 test_cb_resp_t resp;
203
204 rc = ui_pbutton_create(NULL, "Hello", &pbutton);
205 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
206
207 /* Clicked with no callbacks set */
208 ui_pbutton_clicked(pbutton);
209
210 /* Clicked with callback not implementing clicked */
211 ui_pbutton_set_cb(pbutton, &dummy_pbutton_cb, NULL);
212 ui_pbutton_clicked(pbutton);
213
214 /* Clicked with real callback set */
215 resp.clicked = false;
216 ui_pbutton_set_cb(pbutton, &test_pbutton_cb, &resp);
217 ui_pbutton_clicked(pbutton);
218 PCUT_ASSERT_TRUE(resp.clicked);
219
220 ui_pbutton_destroy(pbutton);
221}
222
223/** Press and release button */
224PCUT_TEST(press_release)
225{
226 errno_t rc;
227 gfx_context_t *gc = NULL;
228 test_gc_t tgc;
229 ui_resource_t *resource = NULL;
230 ui_pbutton_t *pbutton;
231 test_cb_resp_t resp;
232
233 memset(&tgc, 0, sizeof(tgc));
234 rc = gfx_context_new(&ops, &tgc, &gc);
235 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
236
237 rc = ui_resource_create(gc, &resource);
238 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
239 PCUT_ASSERT_NOT_NULL(resource);
240
241 rc = ui_pbutton_create(resource, "Hello", &pbutton);
242 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
243
244 resp.clicked = false;
245 ui_pbutton_set_cb(pbutton, &test_pbutton_cb, &resp);
246
247 PCUT_ASSERT_FALSE(pbutton->held);
248 PCUT_ASSERT_FALSE(pbutton->inside);
249
250 ui_pbutton_press(pbutton);
251 PCUT_ASSERT_TRUE(pbutton->held);
252 PCUT_ASSERT_TRUE(pbutton->inside);
253 PCUT_ASSERT_FALSE(resp.clicked);
254
255 ui_pbutton_release(pbutton);
256 PCUT_ASSERT_FALSE(pbutton->held);
257 PCUT_ASSERT_TRUE(pbutton->inside);
258 PCUT_ASSERT_TRUE(resp.clicked);
259
260 ui_pbutton_destroy(pbutton);
261 ui_resource_destroy(resource);
262
263 rc = gfx_context_delete(gc);
264 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
265}
266
267/** Press, leave and release button */
268PCUT_TEST(press_leave_release)
269{
270 errno_t rc;
271 gfx_context_t *gc = NULL;
272 test_gc_t tgc;
273 ui_resource_t *resource = NULL;
274 ui_pbutton_t *pbutton;
275 test_cb_resp_t resp;
276
277 memset(&tgc, 0, sizeof(tgc));
278 rc = gfx_context_new(&ops, &tgc, &gc);
279 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
280
281 rc = ui_resource_create(gc, &resource);
282 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
283 PCUT_ASSERT_NOT_NULL(resource);
284
285 rc = ui_pbutton_create(resource, "Hello", &pbutton);
286 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
287
288 resp.clicked = false;
289 ui_pbutton_set_cb(pbutton, &test_pbutton_cb, &resp);
290
291 PCUT_ASSERT_FALSE(pbutton->held);
292 PCUT_ASSERT_FALSE(pbutton->inside);
293
294 ui_pbutton_press(pbutton);
295 PCUT_ASSERT_TRUE(pbutton->held);
296 PCUT_ASSERT_TRUE(pbutton->inside);
297 PCUT_ASSERT_FALSE(resp.clicked);
298
299 ui_pbutton_leave(pbutton);
300 PCUT_ASSERT_TRUE(pbutton->held);
301 PCUT_ASSERT_FALSE(pbutton->inside);
302 PCUT_ASSERT_FALSE(resp.clicked);
303
304 ui_pbutton_release(pbutton);
305 PCUT_ASSERT_FALSE(pbutton->held);
306 PCUT_ASSERT_FALSE(pbutton->inside);
307 PCUT_ASSERT_FALSE(resp.clicked);
308
309 ui_pbutton_destroy(pbutton);
310 ui_resource_destroy(resource);
311
312 rc = gfx_context_delete(gc);
313 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
314}
315
316/** Press, leave, enter and release button */
317PCUT_TEST(press_leave_enter_release)
318{
319 errno_t rc;
320 gfx_context_t *gc = NULL;
321 test_gc_t tgc;
322 ui_resource_t *resource = NULL;
323 ui_pbutton_t *pbutton;
324 test_cb_resp_t resp;
325
326 memset(&tgc, 0, sizeof(tgc));
327 rc = gfx_context_new(&ops, &tgc, &gc);
328 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
329
330 rc = ui_resource_create(gc, &resource);
331 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
332 PCUT_ASSERT_NOT_NULL(resource);
333
334 rc = ui_pbutton_create(resource, "Hello", &pbutton);
335 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
336
337 resp.clicked = false;
338 ui_pbutton_set_cb(pbutton, &test_pbutton_cb, &resp);
339
340 PCUT_ASSERT_FALSE(pbutton->held);
341 PCUT_ASSERT_FALSE(pbutton->inside);
342
343 ui_pbutton_press(pbutton);
344 PCUT_ASSERT_TRUE(pbutton->held);
345 PCUT_ASSERT_TRUE(pbutton->inside);
346 PCUT_ASSERT_FALSE(resp.clicked);
347
348 ui_pbutton_leave(pbutton);
349 PCUT_ASSERT_TRUE(pbutton->held);
350 PCUT_ASSERT_FALSE(pbutton->inside);
351 PCUT_ASSERT_FALSE(resp.clicked);
352
353 ui_pbutton_enter(pbutton);
354 PCUT_ASSERT_TRUE(pbutton->held);
355 PCUT_ASSERT_TRUE(pbutton->inside);
356 PCUT_ASSERT_FALSE(resp.clicked);
357
358 ui_pbutton_release(pbutton);
359 PCUT_ASSERT_FALSE(pbutton->held);
360 PCUT_ASSERT_TRUE(pbutton->inside);
361 PCUT_ASSERT_TRUE(resp.clicked);
362
363 ui_pbutton_destroy(pbutton);
364 ui_resource_destroy(resource);
365
366 rc = gfx_context_delete(gc);
367 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
368}
369
370/** ui_pos_event() correctly translates POS_PRESS/POS_RELEASE */
371PCUT_TEST(pos_event_press_release)
372{
373 errno_t rc;
374 gfx_context_t *gc = NULL;
375 test_gc_t tgc;
376 ui_resource_t *resource = NULL;
377 ui_pbutton_t *pbutton;
378 ui_evclaim_t claim;
379 pos_event_t event;
380 gfx_rect_t rect;
381
382 memset(&tgc, 0, sizeof(tgc));
383 rc = gfx_context_new(&ops, &tgc, &gc);
384 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
385
386 rc = ui_resource_create(gc, &resource);
387 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
388 PCUT_ASSERT_NOT_NULL(resource);
389
390 rc = ui_pbutton_create(resource, "Hello", &pbutton);
391 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
392
393 PCUT_ASSERT_FALSE(pbutton->held);
394
395 rect.p0.x = 10;
396 rect.p0.y = 20;
397 rect.p1.x = 30;
398 rect.p1.y = 40;
399 ui_pbutton_set_rect(pbutton, &rect);
400
401 /* Press outside is not claimed and does nothing */
402 event.type = POS_PRESS;
403 event.hpos = 9;
404 event.vpos = 20;
405 claim = ui_pbutton_pos_event(pbutton, &event);
406 PCUT_ASSERT_FALSE(pbutton->held);
407 PCUT_ASSERT_EQUALS(ui_unclaimed, claim);
408
409 /* Press inside is claimed and depresses button */
410 event.type = POS_PRESS;
411 event.hpos = 10;
412 event.vpos = 20;
413 claim = ui_pbutton_pos_event(pbutton, &event);
414 PCUT_ASSERT_TRUE(pbutton->held);
415 PCUT_ASSERT_EQUALS(ui_claimed, claim);
416
417 /* Release outside (or anywhere) is claimed and relases button */
418 event.type = POS_RELEASE;
419 event.hpos = 9;
420 event.vpos = 20;
421 claim = ui_pbutton_pos_event(pbutton, &event);
422 PCUT_ASSERT_FALSE(pbutton->held);
423 PCUT_ASSERT_EQUALS(ui_claimed, claim);
424
425 ui_pbutton_destroy(pbutton);
426 ui_resource_destroy(resource);
427
428 rc = gfx_context_delete(gc);
429 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
430}
431
432/** ui_pos_event() correctly translates POS_UPDATE to enter/leave */
433PCUT_TEST(pos_event_enter_leave)
434{
435 errno_t rc;
436 gfx_context_t *gc = NULL;
437 test_gc_t tgc;
438 ui_resource_t *resource = NULL;
439 ui_pbutton_t *pbutton;
440 pos_event_t event;
441 gfx_rect_t rect;
442
443 memset(&tgc, 0, sizeof(tgc));
444 rc = gfx_context_new(&ops, &tgc, &gc);
445 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
446
447 rc = ui_resource_create(gc, &resource);
448 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
449 PCUT_ASSERT_NOT_NULL(resource);
450
451 rc = ui_pbutton_create(resource, "Hello", &pbutton);
452 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
453
454 PCUT_ASSERT_FALSE(pbutton->inside);
455
456 rect.p0.x = 10;
457 rect.p0.y = 20;
458 rect.p1.x = 30;
459 rect.p1.y = 40;
460 ui_pbutton_set_rect(pbutton, &rect);
461
462 /* Moving outside does nothing */
463 event.type = POS_UPDATE;
464 event.hpos = 9;
465 event.vpos = 20;
466 ui_pbutton_pos_event(pbutton, &event);
467 PCUT_ASSERT_FALSE(pbutton->inside);
468
469 /* Moving inside sets inside flag */
470 event.type = POS_UPDATE;
471 event.hpos = 10;
472 event.vpos = 20;
473 ui_pbutton_pos_event(pbutton, &event);
474 PCUT_ASSERT_TRUE(pbutton->inside);
475
476 /* Moving outside clears inside flag */
477 event.type = POS_UPDATE;
478 event.hpos = 9;
479 event.vpos = 20;
480 ui_pbutton_pos_event(pbutton, &event);
481 PCUT_ASSERT_FALSE(pbutton->inside);
482
483 ui_pbutton_destroy(pbutton);
484 ui_resource_destroy(resource);
485
486 rc = gfx_context_delete(gc);
487 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
488}
489
490static errno_t testgc_set_color(void *arg, gfx_color_t *color)
491{
492 (void) arg;
493 (void) color;
494 return EOK;
495}
496
497static errno_t testgc_fill_rect(void *arg, gfx_rect_t *rect)
498{
499 (void) arg;
500 (void) rect;
501 return EOK;
502}
503
504static errno_t testgc_bitmap_create(void *arg, gfx_bitmap_params_t *params,
505 gfx_bitmap_alloc_t *alloc, void **rbm)
506{
507 test_gc_t *tgc = (test_gc_t *) arg;
508 testgc_bitmap_t *tbm;
509
510 tbm = calloc(1, sizeof(testgc_bitmap_t));
511 if (tbm == NULL)
512 return ENOMEM;
513
514 if (alloc == NULL) {
515 tbm->alloc.pitch = (params->rect.p1.x - params->rect.p0.x) *
516 sizeof(uint32_t);
517 tbm->alloc.off0 = 0;
518 tbm->alloc.pixels = calloc(sizeof(uint32_t),
519 (params->rect.p1.x - params->rect.p0.x) *
520 (params->rect.p1.y - params->rect.p0.y));
521 tbm->myalloc = true;
522 if (tbm->alloc.pixels == NULL) {
523 free(tbm);
524 return ENOMEM;
525 }
526 } else {
527 tbm->alloc = *alloc;
528 }
529
530 tbm->tgc = tgc;
531 tgc->bm_created = true;
532 tgc->bm_params = *params;
533 tgc->bm_pixels = tbm->alloc.pixels;
534 *rbm = (void *)tbm;
535 return EOK;
536}
537
538static errno_t testgc_bitmap_destroy(void *bm)
539{
540 testgc_bitmap_t *tbm = (testgc_bitmap_t *)bm;
541 if (tbm->myalloc)
542 free(tbm->alloc.pixels);
543 tbm->tgc->bm_destroyed = true;
544 free(tbm);
545 return EOK;
546}
547
548static errno_t testgc_bitmap_render(void *bm, gfx_rect_t *srect,
549 gfx_coord2_t *offs)
550{
551 testgc_bitmap_t *tbm = (testgc_bitmap_t *)bm;
552 tbm->tgc->bm_rendered = true;
553 tbm->tgc->bm_srect = *srect;
554 tbm->tgc->bm_offs = *offs;
555 return EOK;
556}
557
558static errno_t testgc_bitmap_get_alloc(void *bm, gfx_bitmap_alloc_t *alloc)
559{
560 testgc_bitmap_t *tbm = (testgc_bitmap_t *)bm;
561 *alloc = tbm->alloc;
562 tbm->tgc->bm_got_alloc = true;
563 return EOK;
564}
565
566static void test_pbutton_clicked(ui_pbutton_t *pbutton, void *arg)
567{
568 test_cb_resp_t *resp = (test_cb_resp_t *) arg;
569
570 resp->clicked = true;
571}
572
573PCUT_EXPORT(pbutton);
Note: See TracBrowser for help on using the repository browser.