source: mainline/uspace/lib/ui/src/scrollbar.c@ 8965860c

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

Clickmatic

A class that periodically generates when held, after initial delay.
This is quite similar to the typematic feature found in PC keyboards.
We use it to automatically scroll when scrollbar button or through
is held.

  • Property mode set to 100644
File size: 26.6 KB
Line 
1/*
2 * Copyright (c) 2022 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/** @addtogroup libui
30 * @{
31 */
32/**
33 * @file Scrollbar
34 *
35 * Anatomy of a horizontal scrollbar:
36 *
37 * Up Down
38 * through through
39 * +---+------+--------+---------+---+
40 * | < | | ||| | | > |
41 * +---+------+--------+---------+---+
42 * Up Thumb Down
43 * button button
44 *
45 * +-------- Through --------+
46 *
47 * Scrollbar uses the same terminology whether it is running in horizontal
48 * or vertical mode, in horizontal mode up means left, down means right
49 * (i.e. lower and higher coordinates, respectively).
50 *
51 * The thumb can be dragged to a specific position, resulting in a move
52 * event. The up/down buttons generate up/down events. Pressing a mouse
53 * button on the up/down through generates page up / page down events.
54 *
55 * Pressing and holding down mouse button on up / down button or up / down
56 * through will auto-scroll (using clickmatic).
57 */
58
59#include <errno.h>
60#include <gfx/color.h>
61#include <gfx/context.h>
62#include <gfx/render.h>
63#include <gfx/text.h>
64#include <io/pos_event.h>
65#include <stdlib.h>
66#include <str.h>
67#include <ui/clickmatic.h>
68#include <ui/control.h>
69#include <ui/paint.h>
70#include <ui/pbutton.h>
71#include <ui/scrollbar.h>
72#include <ui/ui.h>
73#include <ui/window.h>
74#include "../private/pbutton.h"
75#include "../private/resource.h"
76#include "../private/scrollbar.h"
77
78enum {
79 /** Scrollbar button width */
80 ui_scrollbar_btn_len = 20,
81 /** Scrollbar button width in text mode */
82 ui_scrollbar_btn_len_text = 1,
83 /** Scrollbar thumb frame thickness */
84 ui_scrollbar_thumb_frame_thickness = 1,
85 /** Scrollbar thumb bevel width */
86 ui_scrollbar_thumb_bevel_width = 2,
87 /** Scrollbar default thumb length */
88 ui_scrollbar_def_thumb_len = 20,
89 /** Scrollbar default thumb length in text mode */
90 ui_scrollbar_def_thumb_len_text = 1,
91 /** Scrollbar minimum thumb length */
92 ui_scrollbar_min_thumb_len = 10,
93 /** Scrollbar minimum thumb length in text mode */
94 ui_scrollbar_min_thumb_len_text = 1,
95};
96
97static void ui_scrollbar_up_btn_down(ui_pbutton_t *, void *);
98static void ui_scrollbar_up_btn_up(ui_pbutton_t *, void *);
99static void ui_scrollbar_down_btn_down(ui_pbutton_t *, void *);
100static void ui_scrollbar_down_btn_up(ui_pbutton_t *, void *);
101static void ui_scrollbar_ctl_destroy(void *);
102static errno_t ui_scrollbar_ctl_paint(void *);
103static ui_evclaim_t ui_scrollbar_ctl_pos_event(void *, pos_event_t *);
104
105static ui_pbutton_cb_t ui_scrollbar_up_btn_cb = {
106 .down = ui_scrollbar_up_btn_down,
107 .up = ui_scrollbar_up_btn_up
108};
109
110static ui_pbutton_cb_t ui_scrollbar_down_btn_cb = {
111 .down = ui_scrollbar_down_btn_down,
112 .up = ui_scrollbar_down_btn_up
113};
114
115/** Scrollbar control ops */
116static ui_control_ops_t ui_scrollbar_ops = {
117 .destroy = ui_scrollbar_ctl_destroy,
118 .paint = ui_scrollbar_ctl_paint,
119 .pos_event = ui_scrollbar_ctl_pos_event
120};
121
122static void ui_scrollbar_cm_up(ui_clickmatic_t *, void *);
123static void ui_scrollbar_cm_down(ui_clickmatic_t *, void *);
124static void ui_scrollbar_cm_page_up(ui_clickmatic_t *, void *);
125static void ui_scrollbar_cm_page_down(ui_clickmatic_t *, void *);
126
127/** Scrollbar clickmatic up callbacks */
128ui_clickmatic_cb_t ui_scrollbar_clickmatic_up_cb = {
129 .clicked = ui_scrollbar_cm_up
130};
131
132/** Scrollbar clickmatic down callbacks */
133ui_clickmatic_cb_t ui_scrollbar_clickmatic_down_cb = {
134 .clicked = ui_scrollbar_cm_down
135};
136
137/** Scrollbar clickmatic page up callbacks */
138ui_clickmatic_cb_t ui_scrollbar_clickmatic_page_up_cb = {
139 .clicked = ui_scrollbar_cm_page_up
140};
141
142/** Scrollbar clickmatic page down callbacks */
143ui_clickmatic_cb_t ui_scrollbar_clickmatic_page_down_cb = {
144 .clicked = ui_scrollbar_cm_page_down
145};
146
147/** Create new scrollbar.
148 *
149 * @param ui UI
150 * @param window Window containing scrollbar
151 * @param rscrollbar Place to store pointer to new scrollbar
152 * @return EOK on success, ENOMEM if out of memory
153 */
154errno_t ui_scrollbar_create(ui_t *ui, ui_window_t *window,
155 ui_scrollbar_t **rscrollbar)
156{
157 ui_scrollbar_t *scrollbar;
158 ui_resource_t *resource;
159 errno_t rc;
160
161 resource = ui_window_get_res(window);
162
163 scrollbar = calloc(1, sizeof(ui_scrollbar_t));
164 if (scrollbar == NULL)
165 return ENOMEM;
166
167 rc = ui_control_new(&ui_scrollbar_ops, (void *) scrollbar,
168 &scrollbar->control);
169 if (rc != EOK) {
170 free(scrollbar);
171 return rc;
172 }
173
174 rc = ui_pbutton_create(resource, resource->textmode ? "\u25c4" : "<",
175 &scrollbar->up_btn);
176 if (rc != EOK)
177 goto error;
178
179 ui_pbutton_set_cb(scrollbar->up_btn, &ui_scrollbar_up_btn_cb,
180 (void *) scrollbar);
181
182 rc = ui_pbutton_create(resource, resource->textmode ? "\u25ba" : ">",
183 &scrollbar->down_btn);
184 if (rc != EOK)
185 goto error;
186
187 ui_pbutton_set_cb(scrollbar->down_btn, &ui_scrollbar_down_btn_cb,
188 (void *) scrollbar);
189
190 scrollbar->thumb_len = resource->textmode ?
191 ui_scrollbar_def_thumb_len_text :
192 ui_scrollbar_def_thumb_len;
193
194 scrollbar->ui = ui;
195 scrollbar->window = window;
196 *rscrollbar = scrollbar;
197 return EOK;
198error:
199 ui_scrollbar_destroy(scrollbar);
200 return rc;
201}
202
203/** Destroy scrollbar.
204 *
205 * @param scrollbar Scrollbar or @c NULL
206 */
207void ui_scrollbar_destroy(ui_scrollbar_t *scrollbar)
208{
209 if (scrollbar == NULL)
210 return;
211
212 ui_pbutton_destroy(scrollbar->up_btn);
213 ui_pbutton_destroy(scrollbar->down_btn);
214 ui_control_delete(scrollbar->control);
215 free(scrollbar);
216}
217
218/** Get base control from scrollbar.
219 *
220 * @param scrollbar Scrollbar
221 * @return Control
222 */
223ui_control_t *ui_scrollbar_ctl(ui_scrollbar_t *scrollbar)
224{
225 return scrollbar->control;
226}
227
228/** Set scrollbar callbacks.
229 *
230 * @param scrollbar Scrollbar
231 * @param cb Scrollbar callbacks
232 * @param arg Callback argument
233 */
234void ui_scrollbar_set_cb(ui_scrollbar_t *scrollbar, ui_scrollbar_cb_t *cb, void *arg)
235{
236 scrollbar->cb = cb;
237 scrollbar->arg = arg;
238}
239
240/** Set scrollbar rectangle.
241 *
242 * @param scrollbar Scrollbar
243 * @param rect New scrollbar rectangle
244 */
245void ui_scrollbar_set_rect(ui_scrollbar_t *scrollbar, gfx_rect_t *rect)
246{
247 ui_scrollbar_geom_t geom;
248
249 scrollbar->rect = *rect;
250
251 ui_scrollbar_get_geom(scrollbar, &geom);
252 ui_pbutton_set_rect(scrollbar->up_btn, &geom.up_btn_rect);
253 ui_pbutton_set_rect(scrollbar->down_btn, &geom.down_btn_rect);
254}
255
256/** Paint outer thumb frame.
257 *
258 * @param scrollbar Scrollbar
259 * @return EOK on success or an error code
260 */
261static errno_t ui_scrollbar_paint_thumb_frame(ui_resource_t *res, gfx_rect_t *rect,
262 gfx_coord_t thickness, gfx_rect_t *inside)
263{
264 gfx_rect_t drect;
265 errno_t rc;
266
267 rc = gfx_set_color(res->gc, res->btn_frame_color);
268 if (rc != EOK)
269 goto error;
270
271 drect.p0.x = rect->p0.x + 1;
272 drect.p0.y = rect->p0.y;
273 drect.p1.x = rect->p1.x - 1;
274 drect.p1.y = rect->p0.y + thickness;
275 rc = gfx_fill_rect(res->gc, &drect);
276 if (rc != EOK)
277 goto error;
278
279 drect.p0.x = rect->p0.x + 1;
280 drect.p0.y = rect->p1.y - thickness;
281 drect.p1.x = rect->p1.x - 1;
282 drect.p1.y = rect->p1.y;
283 rc = gfx_fill_rect(res->gc, &drect);
284 if (rc != EOK)
285 goto error;
286
287 drect.p0.x = rect->p0.x;
288 drect.p0.y = rect->p0.y + 1;
289 drect.p1.x = rect->p0.x + thickness;
290 drect.p1.y = rect->p1.y - 1;
291 rc = gfx_fill_rect(res->gc, &drect);
292 if (rc != EOK)
293 goto error;
294
295 drect.p0.x = rect->p1.x - thickness;
296 drect.p0.y = rect->p0.y + 1;
297 drect.p1.x = rect->p1.x;
298 drect.p1.y = rect->p1.y - 1;
299 rc = gfx_fill_rect(res->gc, &drect);
300 if (rc != EOK)
301 goto error;
302
303 if (inside != NULL) {
304 inside->p0.x = rect->p0.x + thickness;
305 inside->p0.y = rect->p0.y + thickness;
306 inside->p1.x = rect->p1.x - thickness;
307 inside->p1.y = rect->p1.y - thickness;
308 }
309
310 return EOK;
311error:
312 return rc;
313}
314
315/** Paint outset scrollbar bevel.
316 *
317 * @param scrollbar Scrollbar
318 * @return EOK on success or an error code
319 */
320static errno_t ui_scrollbar_paint_outset(ui_scrollbar_t *scrollbar,
321 gfx_rect_t *rect, gfx_rect_t *inside)
322{
323 ui_resource_t *resource = ui_window_get_res(scrollbar->window);
324
325 return ui_paint_bevel(resource->gc, rect,
326 resource->btn_highlight_color,
327 resource->btn_shadow_color, ui_scrollbar_thumb_bevel_width, inside);
328}
329
330/** Determine scrollbar through length.
331 *
332 * Return the size of the space within which the thumb can move
333 * (without subtracting the length of the thumb).
334 *
335 * @param scrollbar Scrollbar
336 * @return Scrollbar through length in pixels
337 */
338gfx_coord_t ui_scrollbar_through_length(ui_scrollbar_t *scrollbar)
339{
340 ui_resource_t *resource;
341 gfx_coord2_t dims;
342 gfx_coord_t w;
343
344 resource = ui_window_get_res(scrollbar->window);
345
346 gfx_rect_dims(&scrollbar->rect, &dims);
347 w = resource->textmode ? ui_scrollbar_btn_len_text :
348 ui_scrollbar_btn_len;
349 return dims.x - 2 * w;
350}
351
352/** Determine scrollbar move length.
353 *
354 * Return the maximum distance the thumb can move.
355 *
356 * @param scrollbar Scrollbar
357 * @return Scrollbar move length in pixels
358 */
359gfx_coord_t ui_scrollbar_move_length(ui_scrollbar_t *scrollbar)
360{
361 return ui_scrollbar_through_length(scrollbar) -
362 scrollbar->thumb_len;
363}
364
365/** Set scrollbar thumb length.
366 *
367 * @param scrollbar Scrollbar
368 * @param len Thumb length in pixels
369 */
370void ui_scrollbar_set_thumb_length(ui_scrollbar_t *scrollbar, gfx_coord_t len)
371{
372 ui_resource_t *resource;
373 gfx_coord_t min_len;
374 gfx_coord_t max_len;
375
376 resource = ui_window_get_res(scrollbar->window);
377
378 min_len = resource->textmode ?
379 ui_scrollbar_min_thumb_len_text :
380 ui_scrollbar_min_thumb_len;
381
382 max_len = ui_scrollbar_through_length(scrollbar);
383 if (len < min_len)
384 len = min_len;
385 if (len > max_len)
386 len = max_len;
387
388 if (len != scrollbar->thumb_len) {
389 scrollbar->thumb_len = len;
390 (void) ui_scrollbar_paint(scrollbar);
391 }
392}
393
394/** Get scrollbar thumb position.
395 *
396 * @param scrollbar Scrollbar
397 * @return Scrollbar thumb position in pixels
398 */
399gfx_coord_t ui_scrollbar_get_pos(ui_scrollbar_t *scrollbar)
400{
401 return scrollbar->pos;
402}
403
404/** Set scrollbar thumb position.
405 *
406 * The position is clipped to the allowed range.
407 *
408 * @param scrollbar Scrollbar
409 * @parap pos Scrollbar thumb position in pixels
410 */
411void ui_scrollbar_set_pos(ui_scrollbar_t *scrollbar, gfx_coord_t pos)
412{
413 gfx_coord_t length;
414
415 length = ui_scrollbar_move_length(scrollbar);
416 if (pos < 0)
417 pos = 0;
418 if (pos > length)
419 pos = length;
420
421 if (pos != scrollbar->pos) {
422 scrollbar->pos = pos;
423 (void) ui_scrollbar_paint(scrollbar);
424 ui_scrollbar_throughs_update(scrollbar,
425 &scrollbar->last_curs_pos);
426 ui_scrollbar_moved(scrollbar, pos);
427 }
428}
429
430/** Paint scrollbar in graphics mode.
431 *
432 * @param scrollbar Scrollbar
433 * @return EOK on success or an error code
434 */
435errno_t ui_scrollbar_paint_gfx(ui_scrollbar_t *scrollbar)
436{
437 ui_resource_t *resource;
438 ui_scrollbar_geom_t geom;
439 gfx_rect_t brect;
440 gfx_rect_t irect;
441 errno_t rc;
442
443 resource = ui_window_get_res(scrollbar->window);
444
445 ui_scrollbar_get_geom(scrollbar, &geom);
446
447 /* Paint scrollbar frame */
448
449 rc = ui_paint_inset_frame(resource, &scrollbar->rect, NULL);
450 if (rc != EOK)
451 goto error;
452
453 /* Paint scrollbar up through */
454 rc = gfx_set_color(resource->gc,
455 scrollbar->up_through_held && scrollbar->up_through_inside ?
456 resource->sbar_act_through_color :
457 resource->sbar_through_color);
458 if (rc != EOK)
459 goto error;
460
461 rc = gfx_fill_rect(resource->gc, &geom.up_through_rect);
462 if (rc != EOK)
463 goto error;
464
465 /* Paint scrollbar down through */
466
467 rc = gfx_set_color(resource->gc,
468 scrollbar->down_through_held && scrollbar->down_through_inside ?
469 resource->sbar_act_through_color :
470 resource->sbar_through_color);
471 if (rc != EOK)
472 goto error;
473
474 rc = gfx_fill_rect(resource->gc, &geom.down_through_rect);
475 if (rc != EOK)
476 goto error;
477
478 /* Paint scrollbar thumb */
479
480 rc = ui_scrollbar_paint_thumb_frame(resource, &geom.thumb_rect,
481 ui_scrollbar_thumb_frame_thickness, &brect);
482 if (rc != EOK)
483 goto error;
484
485 rc = ui_scrollbar_paint_outset(scrollbar, &brect, &irect);
486 if (rc != EOK)
487 goto error;
488
489 rc = gfx_set_color(resource->gc, resource->btn_face_color);
490 if (rc != EOK)
491 goto error;
492
493 rc = gfx_fill_rect(resource->gc, &irect);
494 if (rc != EOK)
495 goto error;
496
497 rc = ui_pbutton_paint(scrollbar->up_btn);
498 if (rc != EOK)
499 goto error;
500
501 rc = ui_pbutton_paint(scrollbar->down_btn);
502 if (rc != EOK)
503 goto error;
504
505 rc = gfx_update(resource->gc);
506 if (rc != EOK)
507 goto error;
508
509 return EOK;
510error:
511 return rc;
512}
513
514/** Paint scrollbar in text mode.
515 *
516 * @param scrollbar Scrollbar
517 * @return EOK on success or an error code
518 */
519errno_t ui_scrollbar_paint_text(ui_scrollbar_t *scrollbar)
520{
521 ui_resource_t *resource;
522 gfx_coord2_t pos;
523 gfx_text_fmt_t fmt;
524 gfx_coord_t w, i;
525 char *buf;
526 const char *gchar;
527 size_t gcharsz;
528 errno_t rc;
529
530 resource = ui_window_get_res(scrollbar->window);
531
532 /* Paint scrollbar through */
533
534 pos = scrollbar->rect.p0;
535 pos.x += ui_scrollbar_btn_len_text;
536
537 gfx_text_fmt_init(&fmt);
538 fmt.font = resource->font;
539 fmt.color = resource->sbar_through_color;
540 fmt.halign = gfx_halign_left;
541 fmt.valign = gfx_valign_top;
542
543 w = scrollbar->rect.p1.x - scrollbar->rect.p0.x -
544 2 * ui_scrollbar_btn_len_text;
545 assert(w >= 0);
546 if (w < 0)
547 return EINVAL;
548
549 gchar = "\u2592";
550 gcharsz = str_size(gchar);
551
552 buf = malloc(w * gcharsz + 1);
553 if (buf == NULL)
554 return ENOMEM;
555
556 for (i = 0; i < w; i++)
557 str_cpy(buf + i * gcharsz, (w - i) * gcharsz + 1, gchar);
558 buf[w * gcharsz] = '\0';
559
560 rc = gfx_puttext(&pos, &fmt, buf);
561 free(buf);
562 if (rc != EOK)
563 goto error;
564
565 /* Paint scrollbar thumb */
566
567 pos.x += scrollbar->pos;
568
569 gchar = "\u25a0";
570 gcharsz = str_size(gchar);
571 w = scrollbar->thumb_len;
572
573 buf = malloc(w * gcharsz + 1);
574 if (buf == NULL)
575 return ENOMEM;
576
577 for (i = 0; i < w; i++)
578 str_cpy(buf + i * gcharsz, (w - i) * gcharsz + 1, gchar);
579 buf[w * gcharsz] = '\0';
580
581 rc = gfx_puttext(&pos, &fmt, buf);
582 free(buf);
583 if (rc != EOK)
584 goto error;
585
586 rc = ui_pbutton_paint(scrollbar->up_btn);
587 if (rc != EOK)
588 goto error;
589
590 rc = ui_pbutton_paint(scrollbar->down_btn);
591 if (rc != EOK)
592 goto error;
593
594 rc = gfx_update(resource->gc);
595 if (rc != EOK)
596 goto error;
597
598 return EOK;
599error:
600 return rc;
601}
602
603/** Paint scrollbar.
604 *
605 * @param scrollbar Scrollbar
606 * @return EOK on success or an error code
607 */
608errno_t ui_scrollbar_paint(ui_scrollbar_t *scrollbar)
609{
610 ui_resource_t *resource = ui_window_get_res(scrollbar->window);
611
612 if (resource->textmode)
613 return ui_scrollbar_paint_text(scrollbar);
614 else
615 return ui_scrollbar_paint_gfx(scrollbar);
616}
617
618/** Get scrollbar geometry.
619 *
620 * @param scrollbar Scrollbar
621 * @param geom Structure to fill in with computed geometry
622 */
623void ui_scrollbar_get_geom(ui_scrollbar_t *scrollbar, ui_scrollbar_geom_t *geom)
624{
625 ui_resource_t *resource;
626 gfx_coord_t btn_len;
627 gfx_rect_t orect;
628 gfx_rect_t irect;
629
630 resource = ui_window_get_res(scrollbar->window);
631
632 if (resource->textmode) {
633 btn_len = ui_scrollbar_btn_len_text;
634 } else {
635 btn_len = ui_scrollbar_btn_len;
636 }
637
638 if (resource->textmode) {
639 irect = scrollbar->rect;
640 orect = scrollbar->rect;
641 } else {
642 ui_paint_get_inset_frame_inside(resource,
643 &scrollbar->rect, &irect);
644 ui_paint_get_bevel_inside(resource->gc,
645 &scrollbar->rect, 1, &orect);
646 }
647
648 /* Up button */
649 geom->up_btn_rect.p0.x = orect.p0.x;
650 geom->up_btn_rect.p0.y = orect.p0.y;
651 geom->up_btn_rect.p1.x = orect.p0.x + btn_len;
652 geom->up_btn_rect.p1.y = orect.p1.y;
653
654 /* Through */
655 geom->through_rect.p0.x = geom->up_btn_rect.p1.x;
656 geom->through_rect.p0.y = irect.p0.y;
657 geom->through_rect.p1.x = orect.p1.x - btn_len;
658 geom->through_rect.p1.y = irect.p1.y;
659
660 /* Thumb */
661 geom->thumb_rect.p0.x = geom->up_btn_rect.p1.x + scrollbar->pos;
662 geom->thumb_rect.p0.y = orect.p0.y;
663 geom->thumb_rect.p1.x = geom->thumb_rect.p0.x + scrollbar->thumb_len;
664 geom->thumb_rect.p1.y = orect.p1.y;
665
666 /* Up through */
667 geom->up_through_rect.p0 = geom->through_rect.p0;
668 geom->up_through_rect.p1.x = geom->thumb_rect.p0.x;
669 geom->up_through_rect.p1.y = geom->through_rect.p1.y;
670
671 /* Down through */
672 geom->down_through_rect.p0.x = geom->thumb_rect.p1.x;
673 geom->down_through_rect.p0.y = geom->through_rect.p0.y;
674 geom->down_through_rect.p1 = geom->through_rect.p1;
675
676 /* Down button */
677 geom->down_btn_rect.p0.x = geom->through_rect.p1.x;
678 geom->down_btn_rect.p0.y = orect.p0.y;
679 geom->down_btn_rect.p1.x = orect.p1.x;
680 geom->down_btn_rect.p1.y = orect.p1.y;
681}
682
683/** Press down scrollbar thumb.
684 *
685 * @param scrollbar Scrollbar
686 * @param pos Pointer position
687 */
688void ui_scrollbar_thumb_press(ui_scrollbar_t *scrollbar, gfx_coord2_t *pos)
689{
690 if (scrollbar->thumb_held)
691 return;
692
693 scrollbar->thumb_held = true;
694 scrollbar->press_pos = *pos;
695 scrollbar->last_pos = scrollbar->pos;
696
697 (void) ui_scrollbar_paint(scrollbar);
698}
699
700/** Press down scrollbar up through.
701 *
702 * @param scrollbar Scrollbar
703 */
704void ui_scrollbar_up_through_press(ui_scrollbar_t *scrollbar)
705{
706 ui_clickmatic_t *clickmatic = ui_get_clickmatic(scrollbar->ui);
707
708 scrollbar->up_through_held = true;
709 scrollbar->up_through_inside = true;
710
711 ui_clickmatic_set_cb(clickmatic, &ui_scrollbar_clickmatic_page_up_cb,
712 (void *) scrollbar);
713 ui_clickmatic_press(clickmatic);
714}
715
716/** Press down scrollbar down through.
717 *
718 * @param scrollbar Scrollbar
719 */
720void ui_scrollbar_down_through_press(ui_scrollbar_t *scrollbar)
721{
722 ui_clickmatic_t *clickmatic = ui_get_clickmatic(scrollbar->ui);
723
724 scrollbar->down_through_held = true;
725 scrollbar->down_through_inside = true;
726
727 ui_clickmatic_set_cb(clickmatic, &ui_scrollbar_clickmatic_page_down_cb,
728 (void *) scrollbar);
729 ui_clickmatic_press(clickmatic);
730}
731
732/** Release scrollbar.
733 *
734 * @param scrollbar Scrollbar
735 * @param pos Pointer position
736 */
737void ui_scrollbar_release(ui_scrollbar_t *scrollbar, gfx_coord2_t *pos)
738{
739 ui_clickmatic_t *clickmatic;
740
741 if (scrollbar->thumb_held) {
742 ui_scrollbar_update(scrollbar, pos);
743 scrollbar->thumb_held = false;
744 }
745
746 if (scrollbar->up_through_held || scrollbar->down_through_held) {
747 clickmatic = ui_get_clickmatic(scrollbar->ui);
748 ui_clickmatic_release(clickmatic);
749 ui_clickmatic_set_cb(clickmatic, NULL, NULL);
750
751 scrollbar->up_through_held = false;
752 scrollbar->down_through_held = false;
753 (void) ui_scrollbar_paint(scrollbar);
754 }
755}
756
757/** Update state of scrollbar throuhgs.
758 *
759 * Update state of scrollbar throughs after mouse cursor or thumb has moved.
760 *
761 * @param scrollbar Scrollbar
762 * @param pos Mouse cursor position
763 */
764void ui_scrollbar_throughs_update(ui_scrollbar_t *scrollbar, gfx_coord2_t *pos)
765{
766 ui_scrollbar_geom_t geom;
767 bool inside_up;
768 bool inside_down;
769
770 ui_scrollbar_get_geom(scrollbar, &geom);
771
772 inside_up = gfx_pix_inside_rect(pos, &geom.up_through_rect);
773 inside_down = gfx_pix_inside_rect(pos, &geom.down_through_rect);
774
775 if (inside_up && !scrollbar->up_through_inside) {
776 scrollbar->up_through_inside = true;
777 (void) ui_scrollbar_paint(scrollbar);
778 } else if (!inside_up && scrollbar->up_through_inside) {
779 scrollbar->up_through_inside = false;
780 (void) ui_scrollbar_paint(scrollbar);
781 }
782
783 if (inside_down && !scrollbar->down_through_inside) {
784 scrollbar->down_through_inside = true;
785 (void) ui_scrollbar_paint(scrollbar);
786 } else if (!inside_down && scrollbar->down_through_inside) {
787 scrollbar->down_through_inside = false;
788 (void) ui_scrollbar_paint(scrollbar);
789 }
790}
791
792/** Pointer moved.
793 *
794 * @param scrollbar Scrollbar
795 * @param pos New pointer position
796 */
797void ui_scrollbar_update(ui_scrollbar_t *scrollbar, gfx_coord2_t *pos)
798{
799 gfx_coord_t spos;
800
801 if (scrollbar->thumb_held) {
802 spos = scrollbar->last_pos + pos->x - scrollbar->press_pos.x;
803 ui_scrollbar_set_pos(scrollbar, spos);
804 }
805
806 ui_scrollbar_throughs_update(scrollbar, pos);
807}
808
809/** Scrollbar up button was pressed.
810 *
811 * @param scrollbar Scrollbar
812 */
813void ui_scrollbar_up(ui_scrollbar_t *scrollbar)
814{
815 if (scrollbar->cb != NULL && scrollbar->cb->up != NULL)
816 scrollbar->cb->up(scrollbar, scrollbar->arg);
817}
818
819/** Scrollbar down button was pressed.
820 *
821 * @param scrollbar Scrollbar
822 */
823void ui_scrollbar_down(ui_scrollbar_t *scrollbar)
824{
825 if (scrollbar->cb != NULL && scrollbar->cb->down != NULL)
826 scrollbar->cb->down(scrollbar, scrollbar->arg);
827}
828
829/** Scrollbar up through was pressed.
830 *
831 * @param scrollbar Scrollbar
832 */
833void ui_scrollbar_page_up(ui_scrollbar_t *scrollbar)
834{
835 if (scrollbar->cb != NULL && scrollbar->cb->page_up != NULL)
836 scrollbar->cb->page_up(scrollbar, scrollbar->arg);
837}
838
839/** Scrollbar down through was pressed.
840 *
841 * @param scrollbar Scrollbar
842 */
843void ui_scrollbar_page_down(ui_scrollbar_t *scrollbar)
844{
845 if (scrollbar->cb != NULL && scrollbar->cb->page_down != NULL)
846 scrollbar->cb->page_down(scrollbar, scrollbar->arg);
847}
848
849/** Scrollbar was moved.
850 *
851 * @param scrollbar Scrollbar
852 */
853void ui_scrollbar_moved(ui_scrollbar_t *scrollbar, gfx_coord_t pos)
854{
855 if (scrollbar->cb != NULL && scrollbar->cb->moved != NULL)
856 scrollbar->cb->moved(scrollbar, scrollbar->arg, pos);
857}
858
859/** Handle scrollbar position event.
860 *
861 * @param scrollbar Scrollbar
862 * @param pos_event Position event
863 * @return @c ui_claimed iff the event is claimed
864 */
865ui_evclaim_t ui_scrollbar_pos_event(ui_scrollbar_t *scrollbar, pos_event_t *event)
866{
867 gfx_coord2_t pos;
868 ui_evclaim_t claimed;
869 ui_scrollbar_geom_t geom;
870
871 ui_scrollbar_get_geom(scrollbar, &geom);
872
873 pos.x = event->hpos;
874 pos.y = event->vpos;
875
876 claimed = ui_pbutton_pos_event(scrollbar->up_btn, event);
877 if (claimed == ui_claimed)
878 return ui_claimed;
879
880 claimed = ui_pbutton_pos_event(scrollbar->down_btn, event);
881 if (claimed == ui_claimed)
882 return ui_claimed;
883
884 switch (event->type) {
885 case POS_PRESS:
886 if (gfx_pix_inside_rect(&pos, &geom.thumb_rect)) {
887 ui_scrollbar_thumb_press(scrollbar, &pos);
888 return ui_claimed;
889 }
890 if (gfx_pix_inside_rect(&pos, &geom.up_through_rect)) {
891 ui_scrollbar_up_through_press(scrollbar);
892 return ui_claimed;
893 }
894 if (gfx_pix_inside_rect(&pos, &geom.down_through_rect)) {
895 ui_scrollbar_down_through_press(scrollbar);
896 return ui_claimed;
897 }
898 break;
899 case POS_RELEASE:
900 if (scrollbar->thumb_held || scrollbar->up_through_held ||
901 scrollbar->down_through_held) {
902 ui_scrollbar_release(scrollbar, &pos);
903 return ui_claimed;
904 }
905 break;
906 case POS_UPDATE:
907 ui_scrollbar_update(scrollbar, &pos);
908 scrollbar->last_curs_pos = pos;
909 break;
910 case POS_DCLICK:
911 break;
912 }
913
914 return ui_unclaimed;
915}
916
917/** Scrollbar up button pressed.
918 *
919 * @param pbutton Up button
920 * @param arg Argument (ui_scrollbar_t *)
921 */
922static void ui_scrollbar_up_btn_down(ui_pbutton_t *pbutton, void *arg)
923{
924 ui_scrollbar_t *scrollbar = (ui_scrollbar_t *)arg;
925 ui_clickmatic_t *clickmatic = ui_get_clickmatic(scrollbar->ui);
926
927 ui_clickmatic_set_cb(clickmatic, &ui_scrollbar_clickmatic_up_cb,
928 (void *) scrollbar);
929 ui_clickmatic_press(clickmatic);
930}
931
932/** Scrollbar up button released.
933 *
934 * @param pbutton Up button
935 * @param arg Argument (ui_scrollbar_t *)
936 */
937static void ui_scrollbar_up_btn_up(ui_pbutton_t *pbutton, void *arg)
938{
939 ui_scrollbar_t *scrollbar = (ui_scrollbar_t *)arg;
940 ui_clickmatic_t *clickmatic = ui_get_clickmatic(scrollbar->ui);
941
942 ui_clickmatic_release(clickmatic);
943 ui_clickmatic_set_cb(clickmatic, NULL, NULL);
944}
945
946/** Scrollbar down button pressed.
947 *
948 * @param pbutton Down button
949 * @param arg Argument (ui_scrollbar_t *)
950 */
951static void ui_scrollbar_down_btn_down(ui_pbutton_t *pbutton, void *arg)
952{
953 ui_scrollbar_t *scrollbar = (ui_scrollbar_t *)arg;
954 ui_clickmatic_t *clickmatic = ui_get_clickmatic(scrollbar->ui);
955
956 ui_clickmatic_set_cb(clickmatic, &ui_scrollbar_clickmatic_down_cb,
957 (void *) scrollbar);
958 ui_clickmatic_press(clickmatic);
959}
960
961/** Scrollbar down button released.
962 *
963 * @param pbutton Down button
964 * @param arg Argument (ui_scrollbar_t *)
965 */
966static void ui_scrollbar_down_btn_up(ui_pbutton_t *pbutton, void *arg)
967{
968 ui_scrollbar_t *scrollbar = (ui_scrollbar_t *)arg;
969 ui_clickmatic_t *clickmatic = ui_get_clickmatic(scrollbar->ui);
970
971 ui_clickmatic_release(clickmatic);
972 ui_clickmatic_set_cb(clickmatic, NULL, NULL);
973}
974
975/** Destroy scrollbar control.
976 *
977 * @param arg Argument (ui_scrollbar_t *)
978 */
979void ui_scrollbar_ctl_destroy(void *arg)
980{
981 ui_scrollbar_t *scrollbar = (ui_scrollbar_t *) arg;
982
983 ui_scrollbar_destroy(scrollbar);
984}
985
986/** Paint scrollbar control.
987 *
988 * @param arg Argument (ui_scrollbar_t *)
989 * @return EOK on success or an error code
990 */
991errno_t ui_scrollbar_ctl_paint(void *arg)
992{
993 ui_scrollbar_t *scrollbar = (ui_scrollbar_t *) arg;
994
995 return ui_scrollbar_paint(scrollbar);
996}
997
998/** Handle scrollbar control position event.
999 *
1000 * @param arg Argument (ui_scrollbar_t *)
1001 * @param pos_event Position event
1002 * @return @c ui_claimed iff the event is claimed
1003 */
1004ui_evclaim_t ui_scrollbar_ctl_pos_event(void *arg, pos_event_t *event)
1005{
1006 ui_scrollbar_t *scrollbar = (ui_scrollbar_t *)arg;
1007
1008 return ui_scrollbar_pos_event(scrollbar, event);
1009}
1010
1011/** Scrollbar clickmatic up button click event.
1012 *
1013 * @param clickmatic Clickmatic
1014 * @param arg Argument (ui_scrollbar_t *)
1015 */
1016static void ui_scrollbar_cm_up(ui_clickmatic_t *clickmatic, void *arg)
1017{
1018 ui_scrollbar_t *scrollbar = (ui_scrollbar_t *)arg;
1019
1020 if (scrollbar->up_btn->inside)
1021 ui_scrollbar_up(scrollbar);
1022}
1023
1024/** Scrollbar clickmatic down button click event.
1025 *
1026 * @param clickmatic Clickmatic
1027 * @param arg Argument (ui_scrollbar_t *)
1028 */
1029static void ui_scrollbar_cm_down(ui_clickmatic_t *clickmatic, void *arg)
1030{
1031 ui_scrollbar_t *scrollbar = (ui_scrollbar_t *)arg;
1032
1033 if (scrollbar->down_btn->inside)
1034 ui_scrollbar_down(scrollbar);
1035}
1036
1037/** Scrollbar clickmatic up through click event.
1038 *
1039 * @param clickmatic Clickmatic
1040 * @param arg Argument (ui_scrollbar_t *)
1041 */
1042static void ui_scrollbar_cm_page_up(ui_clickmatic_t *clickmatic, void *arg)
1043{
1044 ui_scrollbar_t *scrollbar = (ui_scrollbar_t *)arg;
1045
1046 if (scrollbar->up_through_inside)
1047 ui_scrollbar_page_up(scrollbar);
1048}
1049
1050/** Scrollbar clickmatic down through click event.
1051 *
1052 * @param clickmatic Clickmatic
1053 * @param arg Argument (ui_scrollbar_t *)
1054 */
1055static void ui_scrollbar_cm_page_down(ui_clickmatic_t *clickmatic, void *arg)
1056{
1057 ui_scrollbar_t *scrollbar = (ui_scrollbar_t *)arg;
1058
1059 if (scrollbar->down_through_inside)
1060 ui_scrollbar_page_down(scrollbar);
1061}
1062
1063/** @}
1064 */
Note: See TracBrowser for help on using the repository browser.