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

Last change on this file since d7f7a4a was d7f7a4a, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 4 years ago

Replace some license headers with SPDX identifier

Headers are replaced using tools/transorm-copyright.sh only
when it can be matched verbatim with the license header used
throughout most of the codebase.

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