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

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

Add scroll bar to file list control

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