source: mainline/uspace/lib/ui/test/slider.c@ 77ffa01

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

Slider UI control

  • Property mode set to 100644
File size: 12.0 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/slider.h>
36#include <ui/resource.h>
37#include "../private/slider.h"
38
39PCUT_INIT;
40
41PCUT_TEST_SUITE(slider);
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_slider_moved(ui_slider_t *, void *, gfx_coord_t);
61
62static ui_slider_cb_t test_slider_cb = {
63 .moved = test_slider_moved
64};
65
66static ui_slider_cb_t dummy_slider_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 moved;
88 gfx_coord_t pos;
89} test_cb_resp_t;
90
91/** Create and destroy slider */
92PCUT_TEST(create_destroy)
93{
94 ui_slider_t *slider = NULL;
95 errno_t rc;
96
97 rc = ui_slider_create(NULL, "Hello", &slider);
98 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
99 PCUT_ASSERT_NOT_NULL(slider);
100
101 ui_slider_destroy(slider);
102}
103
104/** ui_slider_destroy() can take NULL argument (no-op) */
105PCUT_TEST(destroy_null)
106{
107 ui_slider_destroy(NULL);
108}
109
110/** ui_slider_ctl() returns control that has a working virtual destructor */
111PCUT_TEST(ctl)
112{
113 ui_slider_t *slider;
114 ui_control_t *control;
115 errno_t rc;
116
117 rc = ui_slider_create(NULL, "Hello", &slider);
118 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
119
120 control = ui_slider_ctl(slider);
121 PCUT_ASSERT_NOT_NULL(control);
122
123 ui_control_destroy(control);
124}
125
126/** Set slider rectangle sets internal field */
127PCUT_TEST(set_rect)
128{
129 ui_slider_t *slider;
130 gfx_rect_t rect;
131 errno_t rc;
132
133 rc = ui_slider_create(NULL, "Hello", &slider);
134 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
135
136 rect.p0.x = 1;
137 rect.p0.y = 2;
138 rect.p1.x = 3;
139 rect.p1.y = 4;
140
141 ui_slider_set_rect(slider, &rect);
142 PCUT_ASSERT_INT_EQUALS(rect.p0.x, slider->rect.p0.x);
143 PCUT_ASSERT_INT_EQUALS(rect.p0.y, slider->rect.p0.y);
144 PCUT_ASSERT_INT_EQUALS(rect.p1.x, slider->rect.p1.x);
145 PCUT_ASSERT_INT_EQUALS(rect.p1.y, slider->rect.p1.y);
146
147 ui_slider_destroy(slider);
148}
149
150/** Paint slider */
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_slider_t *slider;
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_slider_create(resource, "Hello", &slider);
168 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
169
170 rc = ui_slider_paint(slider);
171 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
172
173 ui_slider_destroy(slider);
174 ui_resource_destroy(resource);
175
176 rc = gfx_context_delete(gc);
177 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
178}
179
180/** Test ui_slider_moved() */
181PCUT_TEST(moved)
182{
183 errno_t rc;
184 ui_slider_t *slider;
185 test_cb_resp_t resp;
186
187 rc = ui_slider_create(NULL, "Hello", &slider);
188 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
189
190 /* Moved with no callbacks set */
191 ui_slider_moved(slider, 42);
192
193 /* Moved with callback not implementing clicked */
194 ui_slider_set_cb(slider, &dummy_slider_cb, NULL);
195 ui_slider_moved(slider, 42);
196
197 /* Moved with real callback set */
198 resp.moved = false;
199 resp.pos = 0;
200 ui_slider_set_cb(slider, &test_slider_cb, &resp);
201 ui_slider_moved(slider, 42);
202 PCUT_ASSERT_TRUE(resp.moved);
203 PCUT_ASSERT_INT_EQUALS(42, resp.pos);
204
205 ui_slider_destroy(slider);
206}
207
208/** Press and release slider */
209PCUT_TEST(press_release)
210{
211 errno_t rc;
212 gfx_context_t *gc = NULL;
213 test_gc_t tgc;
214 ui_resource_t *resource = NULL;
215 gfx_coord2_t pos;
216 gfx_rect_t rect;
217 ui_slider_t *slider;
218 test_cb_resp_t resp;
219
220 memset(&tgc, 0, sizeof(tgc));
221 rc = gfx_context_new(&ops, &tgc, &gc);
222 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
223
224 rc = ui_resource_create(gc, &resource);
225 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
226 PCUT_ASSERT_NOT_NULL(resource);
227
228 rc = ui_slider_create(resource, "Hello", &slider);
229 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
230
231 rect.p0.x = 10;
232 rect.p0.y = 20;
233 rect.p1.x = 110;
234 rect.p1.y = 120;
235 ui_slider_set_rect(slider, &rect);
236
237 resp.moved = false;
238 ui_slider_set_cb(slider, &test_slider_cb, &resp);
239
240 PCUT_ASSERT_FALSE(slider->held);
241
242 pos.x = 11;
243 pos.y = 22;
244
245 ui_slider_press(slider, &pos);
246 PCUT_ASSERT_TRUE(slider->held);
247 PCUT_ASSERT_FALSE(resp.moved);
248
249 pos.x = 21;
250 pos.y = 32;
251
252 ui_slider_release(slider, &pos);
253 PCUT_ASSERT_FALSE(slider->held);
254 PCUT_ASSERT_TRUE(resp.moved);
255 PCUT_ASSERT_INT_EQUALS(10, slider->pos);
256
257 ui_slider_destroy(slider);
258 ui_resource_destroy(resource);
259
260 rc = gfx_context_delete(gc);
261 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
262}
263
264/** Press, update and release slider */
265PCUT_TEST(press_uodate_release)
266{
267 errno_t rc;
268 gfx_context_t *gc = NULL;
269 test_gc_t tgc;
270 ui_resource_t *resource = NULL;
271 gfx_coord2_t pos;
272 gfx_rect_t rect;
273 ui_slider_t *slider;
274 test_cb_resp_t resp;
275
276 memset(&tgc, 0, sizeof(tgc));
277 rc = gfx_context_new(&ops, &tgc, &gc);
278 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
279
280 rc = ui_resource_create(gc, &resource);
281 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
282 PCUT_ASSERT_NOT_NULL(resource);
283
284 rc = ui_slider_create(resource, "Hello", &slider);
285 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
286
287 rect.p0.x = 10;
288 rect.p0.y = 20;
289 rect.p1.x = 110;
290 rect.p1.y = 120;
291 ui_slider_set_rect(slider, &rect);
292
293 resp.moved = false;
294 ui_slider_set_cb(slider, &test_slider_cb, &resp);
295
296 PCUT_ASSERT_FALSE(slider->held);
297
298 pos.x = 11;
299 pos.y = 22;
300
301 ui_slider_press(slider, &pos);
302 PCUT_ASSERT_TRUE(slider->held);
303 PCUT_ASSERT_FALSE(resp.moved);
304
305 pos.x = 21;
306 pos.y = 32;
307
308 ui_slider_update(slider, &pos);
309 PCUT_ASSERT_TRUE(slider->held);
310 PCUT_ASSERT_TRUE(resp.moved);
311 PCUT_ASSERT_INT_EQUALS(10, slider->pos);
312
313 pos.x = 31;
314 pos.y = 42;
315
316 ui_slider_release(slider, &pos);
317 PCUT_ASSERT_FALSE(slider->held);
318 PCUT_ASSERT_TRUE(resp.moved);
319 PCUT_ASSERT_INT_EQUALS(20, slider->pos);
320
321 ui_slider_destroy(slider);
322 ui_resource_destroy(resource);
323
324 rc = gfx_context_delete(gc);
325 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
326}
327
328/** ui_pos_event() correctly translates POS_PRESS/POS_RELEASE */
329PCUT_TEST(pos_event_press_release)
330{
331 errno_t rc;
332 gfx_context_t *gc = NULL;
333 test_gc_t tgc;
334 ui_resource_t *resource = NULL;
335 ui_slider_t *slider;
336 ui_evclaim_t claim;
337 pos_event_t event;
338 gfx_rect_t rect;
339
340 memset(&tgc, 0, sizeof(tgc));
341 rc = gfx_context_new(&ops, &tgc, &gc);
342 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
343
344 rc = ui_resource_create(gc, &resource);
345 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
346 PCUT_ASSERT_NOT_NULL(resource);
347
348 rc = ui_slider_create(resource, "Hello", &slider);
349 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
350
351 PCUT_ASSERT_FALSE(slider->held);
352
353 rect.p0.x = 10;
354 rect.p0.y = 20;
355 rect.p1.x = 30;
356 rect.p1.y = 40;
357 ui_slider_set_rect(slider, &rect);
358
359 /* Press outside is not claimed and does nothing */
360 event.type = POS_PRESS;
361 event.hpos = 1;
362 event.vpos = 2;
363 claim = ui_slider_pos_event(slider, &event);
364 PCUT_ASSERT_FALSE(slider->held);
365 PCUT_ASSERT_EQUALS(ui_unclaimed, claim);
366
367 /* Press inside is claimed and depresses slider */
368 event.type = POS_PRESS;
369 event.hpos = 11;
370 event.vpos = 22;
371 claim = ui_slider_pos_event(slider, &event);
372 PCUT_ASSERT_TRUE(slider->held);
373 PCUT_ASSERT_EQUALS(ui_claimed, claim);
374
375 /* Release outside (or anywhere) is claimed and relases slider */
376 event.type = POS_RELEASE;
377 event.hpos = 41;
378 event.vpos = 32;
379 claim = ui_slider_pos_event(slider, &event);
380 PCUT_ASSERT_FALSE(slider->held);
381 PCUT_ASSERT_EQUALS(ui_claimed, claim);
382
383 ui_slider_destroy(slider);
384 ui_resource_destroy(resource);
385
386 rc = gfx_context_delete(gc);
387 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
388}
389
390/** ui_slider_length() correctly determines slider length */
391PCUT_TEST(length)
392{
393 errno_t rc;
394 gfx_context_t *gc = NULL;
395 test_gc_t tgc;
396 ui_resource_t *resource = NULL;
397 ui_slider_t *slider;
398 gfx_coord_t length;
399 gfx_rect_t rect;
400
401 memset(&tgc, 0, sizeof(tgc));
402 rc = gfx_context_new(&ops, &tgc, &gc);
403 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
404
405 rc = ui_resource_create(gc, &resource);
406 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
407 PCUT_ASSERT_NOT_NULL(resource);
408
409 rc = ui_slider_create(resource, "Hello", &slider);
410 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
411
412 PCUT_ASSERT_FALSE(slider->held);
413
414 rect.p0.x = 10;
415 rect.p0.y = 20;
416 rect.p1.x = 110;
417 rect.p1.y = 120;
418 ui_slider_set_rect(slider, &rect);
419
420 length = ui_slider_length(slider);
421 PCUT_ASSERT_INT_EQUALS(110 - 10 - 15, length);
422
423 ui_slider_destroy(slider);
424 ui_resource_destroy(resource);
425
426 rc = gfx_context_delete(gc);
427 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
428}
429
430static errno_t testgc_set_color(void *arg, gfx_color_t *color)
431{
432 (void) arg;
433 (void) color;
434 return EOK;
435}
436
437static errno_t testgc_fill_rect(void *arg, gfx_rect_t *rect)
438{
439 (void) arg;
440 (void) rect;
441 return EOK;
442}
443
444static errno_t testgc_bitmap_create(void *arg, gfx_bitmap_params_t *params,
445 gfx_bitmap_alloc_t *alloc, void **rbm)
446{
447 test_gc_t *tgc = (test_gc_t *) arg;
448 testgc_bitmap_t *tbm;
449
450 tbm = calloc(1, sizeof(testgc_bitmap_t));
451 if (tbm == NULL)
452 return ENOMEM;
453
454 if (alloc == NULL) {
455 tbm->alloc.pitch = (params->rect.p1.x - params->rect.p0.x) *
456 sizeof(uint32_t);
457 tbm->alloc.off0 = 0;
458 tbm->alloc.pixels = calloc(sizeof(uint32_t),
459 (params->rect.p1.x - params->rect.p0.x) *
460 (params->rect.p1.y - params->rect.p0.y));
461 tbm->myalloc = true;
462 if (tbm->alloc.pixels == NULL) {
463 free(tbm);
464 return ENOMEM;
465 }
466 } else {
467 tbm->alloc = *alloc;
468 }
469
470 tbm->tgc = tgc;
471 tgc->bm_created = true;
472 tgc->bm_params = *params;
473 tgc->bm_pixels = tbm->alloc.pixels;
474 *rbm = (void *)tbm;
475 return EOK;
476}
477
478static errno_t testgc_bitmap_destroy(void *bm)
479{
480 testgc_bitmap_t *tbm = (testgc_bitmap_t *)bm;
481 if (tbm->myalloc)
482 free(tbm->alloc.pixels);
483 tbm->tgc->bm_destroyed = true;
484 free(tbm);
485 return EOK;
486}
487
488static errno_t testgc_bitmap_render(void *bm, gfx_rect_t *srect,
489 gfx_coord2_t *offs)
490{
491 testgc_bitmap_t *tbm = (testgc_bitmap_t *)bm;
492 tbm->tgc->bm_rendered = true;
493 tbm->tgc->bm_srect = *srect;
494 tbm->tgc->bm_offs = *offs;
495 return EOK;
496}
497
498static errno_t testgc_bitmap_get_alloc(void *bm, gfx_bitmap_alloc_t *alloc)
499{
500 testgc_bitmap_t *tbm = (testgc_bitmap_t *)bm;
501 *alloc = tbm->alloc;
502 tbm->tgc->bm_got_alloc = true;
503 return EOK;
504}
505
506static void test_slider_moved(ui_slider_t *slider, void *arg, gfx_coord_t pos)
507{
508 test_cb_resp_t *resp = (test_cb_resp_t *) arg;
509
510 resp->moved = true;
511 resp->pos = pos;
512}
513
514PCUT_EXPORT(slider);
Note: See TracBrowser for help on using the repository browser.