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

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

Add GC operation to set clipping rectangle

The number of changed files is due to the proliferation of GC
implementations, mostly these are just dummies in unit tests.
Definitely need to tame those in the future.

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