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

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

Scrollbar needs custom button decorations

Push button now allows setting a 'custom decoration' which means
instead of painting the button text a callback function is invoked
to paint the decoration.

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