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

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

Scrollbar buttons should not depress in text mode

  • 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 ui_scrollbar_moved(scrollbar, pos);
464 }
465}
466
467/** Paint scrollbar in graphics mode.
468 *
469 * @param scrollbar Scrollbar
470 * @return EOK on success or an error code
471 */
472errno_t ui_scrollbar_paint_gfx(ui_scrollbar_t *scrollbar)
473{
474 ui_resource_t *resource;
475 ui_scrollbar_geom_t geom;
476 gfx_rect_t brect;
477 gfx_rect_t irect;
478 errno_t rc;
479
480 resource = ui_window_get_res(scrollbar->window);
481
482 ui_scrollbar_get_geom(scrollbar, &geom);
483
484 /* Paint scrollbar frame */
485
486 rc = ui_paint_inset_frame(resource, &scrollbar->rect, NULL);
487 if (rc != EOK)
488 goto error;
489
490 /* Paint scrollbar up through */
491 rc = gfx_set_color(resource->gc,
492 scrollbar->up_through_held && scrollbar->up_through_inside ?
493 resource->sbar_act_through_color :
494 resource->sbar_through_color);
495 if (rc != EOK)
496 goto error;
497
498 rc = gfx_fill_rect(resource->gc, &geom.up_through_rect);
499 if (rc != EOK)
500 goto error;
501
502 /* Paint scrollbar down through */
503
504 rc = gfx_set_color(resource->gc,
505 scrollbar->down_through_held && scrollbar->down_through_inside ?
506 resource->sbar_act_through_color :
507 resource->sbar_through_color);
508 if (rc != EOK)
509 goto error;
510
511 rc = gfx_fill_rect(resource->gc, &geom.down_through_rect);
512 if (rc != EOK)
513 goto error;
514
515 /* Paint scrollbar thumb */
516 rc = ui_scrollbar_paint_thumb_frame(resource, &geom.thumb_rect,
517 ui_scrollbar_thumb_frame_thickness, &brect);
518 if (rc != EOK)
519 goto error;
520
521 rc = ui_scrollbar_paint_outset(scrollbar, &brect, &irect);
522 if (rc != EOK)
523 goto error;
524
525 rc = gfx_set_color(resource->gc, resource->btn_face_color);
526 if (rc != EOK)
527 goto error;
528
529 rc = gfx_fill_rect(resource->gc, &irect);
530 if (rc != EOK)
531 goto error;
532
533 rc = ui_pbutton_paint(scrollbar->up_btn);
534 if (rc != EOK)
535 goto error;
536
537 rc = ui_pbutton_paint(scrollbar->down_btn);
538 if (rc != EOK)
539 goto error;
540
541 rc = gfx_update(resource->gc);
542 if (rc != EOK)
543 goto error;
544
545 return EOK;
546error:
547 return rc;
548}
549
550/** Paint scrollbar in text mode.
551 *
552 * @param scrollbar Scrollbar
553 * @return EOK on success or an error code
554 */
555errno_t ui_scrollbar_paint_text(ui_scrollbar_t *scrollbar)
556{
557 ui_resource_t *resource;
558 ui_scrollbar_geom_t geom;
559 errno_t rc;
560
561 resource = ui_window_get_res(scrollbar->window);
562 ui_scrollbar_get_geom(scrollbar, &geom);
563
564 /* Paint scrollbar through */
565
566 rc = ui_paint_text_rect(resource, &geom.through_rect,
567 resource->sbar_through_color, "\u2592");
568 if (rc != EOK)
569 goto error;
570
571 /* Paint scrollbar thumb */
572
573 rc = ui_paint_text_rect(resource, &geom.thumb_rect,
574 resource->sbar_through_color, "\u25a0");
575 if (rc != EOK)
576 goto error;
577
578 /* Paint buttons */
579
580 rc = ui_pbutton_paint(scrollbar->up_btn);
581 if (rc != EOK)
582 goto error;
583
584 rc = ui_pbutton_paint(scrollbar->down_btn);
585 if (rc != EOK)
586 goto error;
587
588 rc = gfx_update(resource->gc);
589 if (rc != EOK)
590 goto error;
591
592 return EOK;
593error:
594 return rc;
595}
596
597/** Paint scrollbar.
598 *
599 * @param scrollbar Scrollbar
600 * @return EOK on success or an error code
601 */
602errno_t ui_scrollbar_paint(ui_scrollbar_t *scrollbar)
603{
604 ui_resource_t *resource = ui_window_get_res(scrollbar->window);
605
606 if (resource->textmode) {
607 return ui_scrollbar_paint_text(scrollbar);
608 } else {
609 return ui_scrollbar_paint_gfx(scrollbar);
610 }
611}
612
613/** Get scrollbar geometry.
614 *
615 * @param scrollbar Scrollbar
616 * @param geom Structure to fill in with computed geometry
617 */
618void ui_scrollbar_get_geom(ui_scrollbar_t *scrollbar, ui_scrollbar_geom_t *geom)
619{
620 ui_resource_t *resource;
621 gfx_coord_t btn_len;
622 gfx_rect_t orect;
623 gfx_rect_t irect;
624
625 resource = ui_window_get_res(scrollbar->window);
626
627 if (resource->textmode) {
628 btn_len = ui_scrollbar_btn_len_text;
629 } else {
630 btn_len = ui_scrollbar_btn_len;
631 }
632
633 if (resource->textmode) {
634 irect = scrollbar->rect;
635 orect = scrollbar->rect;
636 } else {
637 ui_paint_get_inset_frame_inside(resource,
638 &scrollbar->rect, &irect);
639 ui_paint_get_bevel_inside(resource->gc,
640 &scrollbar->rect, 1, &orect);
641 }
642
643 if (scrollbar->dir == ui_sbd_horiz) {
644 /* Up button */
645 geom->up_btn_rect.p0.x = orect.p0.x;
646 geom->up_btn_rect.p0.y = orect.p0.y;
647 geom->up_btn_rect.p1.x = orect.p0.x + btn_len;
648 geom->up_btn_rect.p1.y = orect.p1.y;
649
650 /* Through */
651 geom->through_rect.p0.x = geom->up_btn_rect.p1.x;
652 geom->through_rect.p0.y = irect.p0.y;
653 geom->through_rect.p1.x = orect.p1.x - btn_len;
654 geom->through_rect.p1.y = irect.p1.y;
655
656 /* Thumb */
657 geom->thumb_rect.p0.x = geom->up_btn_rect.p1.x +
658 scrollbar->pos;
659 geom->thumb_rect.p0.y = orect.p0.y;
660 geom->thumb_rect.p1.x = geom->thumb_rect.p0.x +
661 scrollbar->thumb_len;
662 geom->thumb_rect.p1.y = orect.p1.y;
663
664 /* Up through */
665 geom->up_through_rect.p0 = geom->through_rect.p0;
666 geom->up_through_rect.p1.x = geom->thumb_rect.p0.x;
667 geom->up_through_rect.p1.y = geom->through_rect.p1.y;
668
669 /* Down through */
670 geom->down_through_rect.p0.x = geom->thumb_rect.p1.x;
671 geom->down_through_rect.p0.y = geom->through_rect.p0.y;
672 geom->down_through_rect.p1 = geom->through_rect.p1;
673
674 /* Down button */
675 geom->down_btn_rect.p0.x = geom->through_rect.p1.x;
676 geom->down_btn_rect.p0.y = orect.p0.y;
677 geom->down_btn_rect.p1.x = orect.p1.x;
678 geom->down_btn_rect.p1.y = orect.p1.y;
679 } else {
680 /* Up button */
681 geom->up_btn_rect.p0.x = orect.p0.x;
682 geom->up_btn_rect.p0.y = orect.p0.y;
683 geom->up_btn_rect.p1.x = orect.p1.x;
684 geom->up_btn_rect.p1.y = orect.p0.y + btn_len;
685
686 /* Through */
687 geom->through_rect.p0.x = irect.p0.x;
688 geom->through_rect.p0.y = geom->up_btn_rect.p1.y;
689 geom->through_rect.p1.x = irect.p1.x;
690 geom->through_rect.p1.y = orect.p1.y - btn_len;
691
692 /* Thumb */
693 geom->thumb_rect.p0.x = orect.p0.x;
694 geom->thumb_rect.p0.y = geom->up_btn_rect.p1.y +
695 scrollbar->pos;
696 geom->thumb_rect.p1.x = orect.p1.x;
697 geom->thumb_rect.p1.y = geom->thumb_rect.p0.y +
698 scrollbar->thumb_len;
699
700 /* Up through */
701 geom->up_through_rect.p0 = geom->through_rect.p0;
702 geom->up_through_rect.p1.x = geom->through_rect.p1.x;
703 geom->up_through_rect.p1.y = geom->thumb_rect.p0.y;
704
705 /* Down through */
706 geom->down_through_rect.p0.x = geom->through_rect.p0.x;
707 geom->down_through_rect.p0.y = geom->thumb_rect.p1.y;
708 geom->down_through_rect.p1 = geom->through_rect.p1;
709
710 /* Down button */
711 geom->down_btn_rect.p0.x = orect.p0.x;
712 geom->down_btn_rect.p0.y = geom->through_rect.p1.y;
713 geom->down_btn_rect.p1.x = orect.p1.x;
714 geom->down_btn_rect.p1.y = orect.p1.y;
715 }
716}
717
718/** Press down scrollbar thumb.
719 *
720 * @param scrollbar Scrollbar
721 * @param pos Pointer position
722 */
723void ui_scrollbar_thumb_press(ui_scrollbar_t *scrollbar, gfx_coord2_t *pos)
724{
725 if (scrollbar->thumb_held)
726 return;
727
728 scrollbar->thumb_held = true;
729 scrollbar->press_pos = *pos;
730 scrollbar->last_pos = scrollbar->pos;
731
732 (void) ui_scrollbar_paint(scrollbar);
733}
734
735/** Press down scrollbar up through.
736 *
737 * @param scrollbar Scrollbar
738 */
739void ui_scrollbar_up_through_press(ui_scrollbar_t *scrollbar)
740{
741 ui_clickmatic_t *clickmatic = ui_get_clickmatic(scrollbar->ui);
742
743 scrollbar->up_through_held = true;
744 scrollbar->up_through_inside = true;
745
746 ui_clickmatic_set_cb(clickmatic, &ui_scrollbar_clickmatic_page_up_cb,
747 (void *) scrollbar);
748 ui_clickmatic_press(clickmatic);
749}
750
751/** Press down scrollbar down through.
752 *
753 * @param scrollbar Scrollbar
754 */
755void ui_scrollbar_down_through_press(ui_scrollbar_t *scrollbar)
756{
757 ui_clickmatic_t *clickmatic = ui_get_clickmatic(scrollbar->ui);
758
759 scrollbar->down_through_held = true;
760 scrollbar->down_through_inside = true;
761
762 ui_clickmatic_set_cb(clickmatic, &ui_scrollbar_clickmatic_page_down_cb,
763 (void *) scrollbar);
764 ui_clickmatic_press(clickmatic);
765}
766
767/** Release scrollbar.
768 *
769 * @param scrollbar Scrollbar
770 * @param pos Pointer position
771 */
772void ui_scrollbar_release(ui_scrollbar_t *scrollbar, gfx_coord2_t *pos)
773{
774 ui_clickmatic_t *clickmatic;
775
776 if (scrollbar->thumb_held) {
777 ui_scrollbar_update(scrollbar, pos);
778 scrollbar->thumb_held = false;
779 }
780
781 if (scrollbar->up_through_held || scrollbar->down_through_held) {
782 clickmatic = ui_get_clickmatic(scrollbar->ui);
783 ui_clickmatic_release(clickmatic);
784 ui_clickmatic_set_cb(clickmatic, NULL, NULL);
785
786 scrollbar->up_through_held = false;
787 scrollbar->down_through_held = false;
788 (void) ui_scrollbar_paint(scrollbar);
789 }
790}
791
792/** Update state of scrollbar throuhgs.
793 *
794 * Update state of scrollbar throughs after mouse cursor or thumb has moved.
795 *
796 * @param scrollbar Scrollbar
797 * @param pos Mouse cursor position
798 */
799void ui_scrollbar_throughs_update(ui_scrollbar_t *scrollbar, gfx_coord2_t *pos)
800{
801 ui_scrollbar_geom_t geom;
802 bool inside_up;
803 bool inside_down;
804
805 ui_scrollbar_get_geom(scrollbar, &geom);
806
807 inside_up = gfx_pix_inside_rect(pos, &geom.up_through_rect);
808 inside_down = gfx_pix_inside_rect(pos, &geom.down_through_rect);
809
810 if (inside_up && !scrollbar->up_through_inside) {
811 scrollbar->up_through_inside = true;
812 (void) ui_scrollbar_paint(scrollbar);
813 } else if (!inside_up && scrollbar->up_through_inside) {
814 scrollbar->up_through_inside = false;
815 (void) ui_scrollbar_paint(scrollbar);
816 }
817
818 if (inside_down && !scrollbar->down_through_inside) {
819 scrollbar->down_through_inside = true;
820 (void) ui_scrollbar_paint(scrollbar);
821 } else if (!inside_down && scrollbar->down_through_inside) {
822 scrollbar->down_through_inside = false;
823 (void) ui_scrollbar_paint(scrollbar);
824 }
825}
826
827/** Scrollbar handler for pointer movement.
828 *
829 * @param scrollbar Scrollbar
830 * @param pos New pointer position
831 */
832void ui_scrollbar_update(ui_scrollbar_t *scrollbar, gfx_coord2_t *pos)
833{
834 gfx_coord_t spos;
835
836 if (scrollbar->thumb_held) {
837 if (scrollbar->dir == ui_sbd_horiz)
838 spos = scrollbar->last_pos + pos->x - scrollbar->press_pos.x;
839 else
840 spos = scrollbar->last_pos + pos->y - scrollbar->press_pos.y;
841
842 ui_scrollbar_set_pos(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.