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

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

Generating button activation event

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