source: mainline/uspace/lib/ui/src/filelist.c@ 54ddb59

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

Base navigator panel on UI file list

Free scrollbar!

  • Property mode set to 100644
File size: 36.3 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/** @file File list.
33 *
34 * Displays a file listing.
35 */
36
37#include <dirent.h>
38#include <errno.h>
39#include <gfx/render.h>
40#include <gfx/text.h>
41#include <stdlib.h>
42#include <str.h>
43#include <ui/control.h>
44#include <ui/filelist.h>
45#include <ui/paint.h>
46#include <ui/resource.h>
47#include <ui/scrollbar.h>
48#include <vfs/vfs.h>
49#include <qsort.h>
50#include "../private/filelist.h"
51#include "../private/resource.h"
52
53static void ui_file_list_ctl_destroy(void *);
54static errno_t ui_file_list_ctl_paint(void *);
55static ui_evclaim_t ui_file_list_ctl_kbd_event(void *, kbd_event_t *);
56static ui_evclaim_t ui_file_list_ctl_pos_event(void *, pos_event_t *);
57
58/** File list control ops */
59ui_control_ops_t ui_file_list_ctl_ops = {
60 .destroy = ui_file_list_ctl_destroy,
61 .paint = ui_file_list_ctl_paint,
62 .kbd_event = ui_file_list_ctl_kbd_event,
63 .pos_event = ui_file_list_ctl_pos_event
64};
65
66enum {
67 file_list_entry_hpad = 2,
68 file_list_entry_vpad = 2,
69 file_list_entry_hpad_text = 1,
70 file_list_entry_vpad_text = 0,
71};
72
73static void ui_file_list_scrollbar_up(ui_scrollbar_t *, void *);
74static void ui_file_list_scrollbar_down(ui_scrollbar_t *, void *);
75static void ui_file_list_scrollbar_page_up(ui_scrollbar_t *, void *);
76static void ui_file_list_scrollbar_page_down(ui_scrollbar_t *, void *);
77static void ui_file_list_scrollbar_moved(ui_scrollbar_t *, void *, gfx_coord_t);
78
79/** File list scrollbar callbacks */
80static ui_scrollbar_cb_t ui_file_list_scrollbar_cb = {
81 .up = ui_file_list_scrollbar_up,
82 .down = ui_file_list_scrollbar_down,
83 .page_up = ui_file_list_scrollbar_page_up,
84 .page_down = ui_file_list_scrollbar_page_down,
85 .moved = ui_file_list_scrollbar_moved
86};
87
88/** Create file list.
89 *
90 * @param window Containing window
91 * @param active @c true iff file list should be active
92 * @param rflist Place to store pointer to new file list
93 * @return EOK on success or an error code
94 */
95errno_t ui_file_list_create(ui_window_t *window, bool active,
96 ui_file_list_t **rflist)
97{
98 ui_file_list_t *flist;
99 errno_t rc;
100
101 flist = calloc(1, sizeof(ui_file_list_t));
102 if (flist == NULL)
103 return ENOMEM;
104
105 rc = ui_control_new(&ui_file_list_ctl_ops, (void *)flist,
106 &flist->control);
107 if (rc != EOK) {
108 free(flist);
109 return rc;
110 }
111
112 rc = gfx_color_new_ega(0x0f, &flist->dir_color);
113 if (rc != EOK)
114 goto error;
115
116 rc = gfx_color_new_ega(0x0a, &flist->svc_color);
117 if (rc != EOK)
118 goto error;
119
120 rc = ui_scrollbar_create(ui_window_get_ui(window), window,
121 ui_sbd_vert, &flist->scrollbar);
122 if (rc != EOK)
123 goto error;
124
125 ui_scrollbar_set_cb(flist->scrollbar, &ui_file_list_scrollbar_cb,
126 (void *) flist);
127
128 flist->window = window;
129 list_initialize(&flist->entries);
130 flist->entries_cnt = 0;
131 flist->active = active;
132
133 *rflist = flist;
134 return EOK;
135error:
136 if (flist->dir_color != NULL)
137 gfx_color_delete(flist->dir_color);
138 if (flist->svc_color != NULL)
139 gfx_color_delete(flist->svc_color);
140 ui_control_delete(flist->control);
141 free(flist);
142 return rc;
143}
144
145/** Destroy file list.
146 *
147 * @param flist File list
148 */
149void ui_file_list_destroy(ui_file_list_t *flist)
150{
151 ui_file_list_clear_entries(flist);
152 ui_control_delete(flist->control);
153 free(flist);
154}
155
156/** Set file list callbacks.
157 *
158 * @param flist File list
159 * @param cb Callbacks
160 * @param arg Argument to callback functions
161 */
162void ui_file_list_set_cb(ui_file_list_t *flist, ui_file_list_cb_t *cb, void *arg)
163{
164 flist->cb = cb;
165 flist->cb_arg = arg;
166}
167
168/** Get height of file list entry.
169 *
170 * @param flist File list
171 * @return Entry height in pixels
172 */
173gfx_coord_t ui_file_list_entry_height(ui_file_list_t *flist)
174{
175 ui_resource_t *res;
176 gfx_font_metrics_t metrics;
177 gfx_coord_t height;
178 gfx_coord_t vpad;
179
180 res = ui_window_get_res(flist->window);
181
182 if (res->textmode) {
183 vpad = file_list_entry_vpad_text;
184 } else {
185 vpad = file_list_entry_vpad;
186 }
187
188 /* Normal menu entry */
189 gfx_font_get_metrics(res->font, &metrics);
190 height = metrics.ascent + metrics.descent + 1;
191
192 return height + 2 * vpad;
193}
194
195/** Paint file list entry.
196 *
197 * @param entry File list entry
198 * @param entry_idx Entry index (within list of entries)
199 * @return EOK on success or an error code
200 */
201errno_t ui_file_list_entry_paint(ui_file_list_entry_t *entry, size_t entry_idx)
202{
203 ui_file_list_t *flist = entry->flist;
204 gfx_context_t *gc = ui_window_get_gc(flist->window);
205 ui_resource_t *res = ui_window_get_res(flist->window);
206 gfx_font_t *font = ui_resource_get_font(res);
207 gfx_text_fmt_t fmt;
208 gfx_coord2_t pos;
209 gfx_rect_t rect;
210 gfx_rect_t lrect;
211 gfx_rect_t crect;
212 gfx_color_t *bgcolor;
213 char *caption;
214 gfx_coord_t hpad, vpad;
215 gfx_coord_t line_height;
216 size_t rows;
217 errno_t rc;
218 int rv;
219
220 line_height = ui_file_list_entry_height(flist);
221 ui_file_list_inside_rect(entry->flist, &lrect);
222
223 gfx_text_fmt_init(&fmt);
224 fmt.font = font;
225 rows = ui_file_list_page_size(flist) + 1;
226
227 /* Do not display entry outside of current page */
228 if (entry_idx < flist->page_idx ||
229 entry_idx >= flist->page_idx + rows)
230 return EOK;
231
232 if (res->textmode) {
233 hpad = file_list_entry_hpad_text;
234 vpad = file_list_entry_vpad_text;
235 } else {
236 hpad = file_list_entry_hpad;
237 vpad = file_list_entry_vpad;
238 }
239
240 pos.x = lrect.p0.x;
241 pos.y = lrect.p0.y + line_height * (entry_idx - flist->page_idx);
242
243 if (entry == flist->cursor && flist->active) {
244 fmt.color = res->entry_sel_text_fg_color;
245 bgcolor = res->entry_sel_text_bg_color;
246 } else if (entry->isdir) {
247 if (res->textmode) {
248 fmt.color = flist->dir_color;
249 bgcolor = flist->dir_color;
250 } else {
251 fmt.color = res->entry_fg_color;
252 bgcolor = res->entry_bg_color;
253 }
254 } else if (entry->svc != 0) {
255 if (res->textmode) {
256 fmt.color = flist->svc_color;
257 bgcolor = flist->svc_color;
258 } else {
259 fmt.color = res->entry_fg_color;
260 bgcolor = res->entry_bg_color;
261 }
262 } else {
263 fmt.color = res->entry_fg_color;
264 bgcolor = res->entry_bg_color;
265 }
266
267 /* Draw entry background */
268 rect.p0 = pos;
269 rect.p1.x = lrect.p1.x;
270 rect.p1.y = rect.p0.y + line_height;
271
272 /* Clip to file list interior */
273 gfx_rect_clip(&rect, &lrect, &crect);
274
275 rc = gfx_set_color(gc, bgcolor);
276 if (rc != EOK)
277 return rc;
278
279 rc = gfx_fill_rect(gc, &crect);
280 if (rc != EOK)
281 return rc;
282
283 /*
284 * Make sure name does not overflow the entry rectangle.
285 *
286 * XXX We probably want to measure the text width, and,
287 * if it's too long, use gfx_text_find_pos() to find where
288 * it should be cut off (and append some sort of overflow
289 * marker.
290 */
291 rc = gfx_set_clip_rect(gc, &crect);
292 if (rc != EOK)
293 return rc;
294
295 pos.x += hpad;
296 pos.y += vpad;
297
298 if (res->textmode || !entry->isdir) {
299 rc = gfx_puttext(&pos, &fmt, entry->name);
300 if (rc != EOK) {
301 (void) gfx_set_clip_rect(gc, NULL);
302 return rc;
303 }
304 } else {
305 /*
306 * XXX This is mostly a hack to distinguish directories
307 * util a better solution is available. (E.g. a Size
308 * column where we can put <dir>, an icon.)
309 */
310 rv = asprintf(&caption, "[%s]", entry->name);
311 if (rv < 0) {
312 (void) gfx_set_clip_rect(gc, NULL);
313 return rc;
314 }
315
316 rc = gfx_puttext(&pos, &fmt, caption);
317 if (rc != EOK) {
318 free(caption);
319 (void) gfx_set_clip_rect(gc, NULL);
320 return rc;
321 }
322
323 free(caption);
324 }
325
326 return gfx_set_clip_rect(gc, NULL);
327}
328
329/** Paint file list.
330 *
331 * @param flist File list
332 */
333errno_t ui_file_list_paint(ui_file_list_t *flist)
334{
335 gfx_context_t *gc = ui_window_get_gc(flist->window);
336 ui_resource_t *res = ui_window_get_res(flist->window);
337 ui_file_list_entry_t *entry;
338 int i, lines;
339 errno_t rc;
340
341 rc = gfx_set_color(gc, res->entry_bg_color);
342 if (rc != EOK)
343 return rc;
344
345 rc = gfx_fill_rect(gc, &flist->rect);
346 if (rc != EOK)
347 return rc;
348
349 if (!res->textmode) {
350 rc = ui_paint_inset_frame(res, &flist->rect, NULL);
351 if (rc != EOK)
352 return rc;
353 }
354
355 lines = ui_file_list_page_size(flist) + 1;
356 i = 0;
357
358 entry = flist->page;
359 while (entry != NULL && i < lines) {
360 rc = ui_file_list_entry_paint(entry, flist->page_idx + i);
361 if (rc != EOK)
362 return rc;
363
364 ++i;
365 entry = ui_file_list_next(entry);
366 }
367
368 rc = ui_scrollbar_paint(flist->scrollbar);
369 if (rc != EOK)
370 return rc;
371
372 rc = gfx_update(gc);
373 if (rc != EOK)
374 return rc;
375
376 return EOK;
377}
378
379/** Handle file list keyboard event.
380 *
381 * @param flist File list
382 * @param event Keyboard event
383 * @return ui_claimed iff event was claimed
384 */
385ui_evclaim_t ui_file_list_kbd_event(ui_file_list_t *flist, kbd_event_t *event)
386{
387 if (!flist->active)
388 return ui_unclaimed;
389
390 if (event->type == KEY_PRESS) {
391 if ((event->mods & (KM_CTRL | KM_ALT | KM_SHIFT)) == 0) {
392 switch (event->key) {
393 case KC_UP:
394 ui_file_list_cursor_up(flist);
395 break;
396 case KC_DOWN:
397 ui_file_list_cursor_down(flist);
398 break;
399 case KC_HOME:
400 ui_file_list_cursor_top(flist);
401 break;
402 case KC_END:
403 ui_file_list_cursor_bottom(flist);
404 break;
405 case KC_PAGE_UP:
406 ui_file_list_page_up(flist);
407 break;
408 case KC_PAGE_DOWN:
409 ui_file_list_page_down(flist);
410 break;
411 case KC_ENTER:
412 ui_file_list_open(flist, flist->cursor);
413 break;
414 default:
415 break;
416 }
417 }
418 }
419
420 return ui_claimed;
421}
422
423/** Handle file list position event.
424 *
425 * @param flist File list
426 * @param event Position event
427 * @return ui_claimed iff event was claimed
428 */
429ui_evclaim_t ui_file_list_pos_event(ui_file_list_t *flist, pos_event_t *event)
430{
431 gfx_coord2_t pos;
432 gfx_rect_t irect;
433 ui_file_list_entry_t *entry;
434 gfx_coord_t line_height;
435 size_t entry_idx;
436 ui_evclaim_t claim;
437 int n;
438
439 claim = ui_scrollbar_pos_event(flist->scrollbar, event);
440 if (claim == ui_claimed)
441 return ui_claimed;
442
443 line_height = ui_file_list_entry_height(flist);
444
445 pos.x = event->hpos;
446 pos.y = event->vpos;
447 if (!gfx_pix_inside_rect(&pos, &flist->rect))
448 return ui_unclaimed;
449
450 if (!flist->active && event->type == POS_PRESS)
451 ui_file_list_activate_req(flist);
452
453 if (event->type == POS_PRESS || event->type == POS_DCLICK) {
454 ui_file_list_inside_rect(flist, &irect);
455
456 /* Did we click on one of the entries? */
457 if (gfx_pix_inside_rect(&pos, &irect)) {
458 /* Index within page */
459 n = (pos.y - irect.p0.y) / line_height;
460
461 /* Entry and its index within entire listing */
462 entry = ui_file_list_page_nth_entry(flist, n, &entry_idx);
463 if (entry == NULL)
464 return ui_claimed;
465
466 if (event->type == POS_PRESS) {
467 /* Move to the entry found */
468 ui_file_list_cursor_move(flist, entry, entry_idx);
469 } else {
470 /* event->type == POS_DCLICK */
471 ui_file_list_open(flist, entry);
472 }
473 } else {
474 /* It's in the border. */
475 if (event->type == POS_PRESS) {
476 /* Top or bottom half? */
477 if (pos.y >= (irect.p0.y + irect.p1.y) / 2)
478 ui_file_list_page_down(flist);
479 else
480 ui_file_list_page_up(flist);
481 }
482 }
483 }
484
485 return ui_claimed;
486}
487
488/** Get base control for file list.
489 *
490 * @param flist File list
491 * @return Base UI control
492 */
493ui_control_t *ui_file_list_ctl(ui_file_list_t *flist)
494{
495 return flist->control;
496}
497
498/** Set file list rectangle.
499 *
500 * @param flist File list
501 * @param rect Rectangle
502 */
503void ui_file_list_set_rect(ui_file_list_t *flist, gfx_rect_t *rect)
504{
505 gfx_rect_t srect;
506
507 flist->rect = *rect;
508
509 ui_file_list_scrollbar_rect(flist, &srect);
510 ui_scrollbar_set_rect(flist->scrollbar, &srect);
511}
512
513/** Get file list page size.
514 *
515 * @param flist File list
516 * @return Number of entries that fit in flist at the same time.
517 */
518unsigned ui_file_list_page_size(ui_file_list_t *flist)
519{
520 gfx_coord_t line_height;
521 gfx_rect_t irect;
522
523 line_height = ui_file_list_entry_height(flist);
524 ui_file_list_inside_rect(flist, &irect);
525 return (irect.p1.y - irect.p0.y) / line_height;
526}
527
528/** Get file list interior rectangle.
529 *
530 * @param flist File list
531 * @param irect Place to store interior rectangle
532 */
533void ui_file_list_inside_rect(ui_file_list_t *flist, gfx_rect_t *irect)
534{
535 ui_resource_t *res = ui_window_get_res(flist->window);
536 gfx_rect_t rect;
537 gfx_coord_t width;
538
539 if (res->textmode) {
540 rect = flist->rect;
541 } else {
542 ui_paint_get_inset_frame_inside(res, &flist->rect, &rect);
543 }
544
545 if (res->textmode) {
546 width = 1;
547 } else {
548 width = 23;
549 }
550
551 irect->p0 = rect.p0;
552 irect->p1.x = rect.p1.x - width;
553 irect->p1.y = rect.p1.y;
554}
555
556/** Get file list scrollbar rectangle.
557 *
558 * @param flist File list
559 * @param irect Place to store interior rectangle
560 */
561void ui_file_list_scrollbar_rect(ui_file_list_t *flist, gfx_rect_t *srect)
562{
563 ui_resource_t *res = ui_window_get_res(flist->window);
564 gfx_rect_t rect;
565 gfx_coord_t width;
566
567 if (res->textmode) {
568 rect = flist->rect;
569 } else {
570 ui_paint_get_inset_frame_inside(res, &flist->rect, &rect);
571 }
572
573 if (res->textmode) {
574 width = 1;
575 } else {
576 width = 23;
577 }
578
579 srect->p0.x = rect.p1.x - width;
580 srect->p0.y = rect.p0.y;
581 srect->p1 = rect.p1;
582}
583
584/** Compute new position for file list scrollbar thumb.
585 *
586 * @param flist File list
587 * @return New position
588 */
589gfx_coord_t ui_file_list_scrollbar_pos(ui_file_list_t *flist)
590{
591 size_t entries;
592 size_t pglen;
593 size_t sbar_len;
594
595 entries = list_count(&flist->entries);
596 pglen = ui_file_list_page_size(flist);
597 sbar_len = ui_scrollbar_move_length(flist->scrollbar);
598
599 if (entries > pglen)
600 return sbar_len * flist->page_idx / (entries - pglen);
601 else
602 return 0;
603}
604
605/** Update file list scrollbar position.
606 *
607 * @param flist File list
608 */
609void ui_file_list_scrollbar_update(ui_file_list_t *flist)
610{
611 ui_scrollbar_set_pos(flist->scrollbar,
612 ui_file_list_scrollbar_pos(flist));
613}
614
615/** Determine if file list is active.
616 *
617 * @param flist File list
618 * @return @c true iff file list is active
619 */
620bool ui_file_list_is_active(ui_file_list_t *flist)
621{
622 return flist->active;
623}
624
625/** Activate file list.
626 *
627 * @param flist File list
628 *
629 * @return EOK on success or an error code
630 */
631errno_t ui_file_list_activate(ui_file_list_t *flist)
632{
633 errno_t rc;
634
635 if (flist->dir != NULL) {
636 rc = vfs_cwd_set(flist->dir);
637 if (rc != EOK)
638 return rc;
639 }
640
641 flist->active = true;
642 (void) ui_file_list_paint(flist);
643 return EOK;
644}
645
646/** Deactivate file list.
647 *
648 * @param flist File list
649 */
650void ui_file_list_deactivate(ui_file_list_t *flist)
651{
652 flist->active = false;
653 (void) ui_file_list_paint(flist);
654}
655
656/** Initialize file list entry attributes.
657 *
658 * @param attr Attributes
659 */
660void ui_file_list_entry_attr_init(ui_file_list_entry_attr_t *attr)
661{
662 memset(attr, 0, sizeof(*attr));
663}
664
665/** Destroy file list control.
666 *
667 * @param arg Argument (ui_file_list_t *)
668 */
669void ui_file_list_ctl_destroy(void *arg)
670{
671 ui_file_list_t *flist = (ui_file_list_t *) arg;
672
673 ui_file_list_destroy(flist);
674}
675
676/** Paint file list control.
677 *
678 * @param arg Argument (ui_file_list_t *)
679 * @return EOK on success or an error code
680 */
681errno_t ui_file_list_ctl_paint(void *arg)
682{
683 ui_file_list_t *flist = (ui_file_list_t *) arg;
684
685 return ui_file_list_paint(flist);
686}
687
688/** Handle file list control keyboard event.
689 *
690 * @param arg Argument (ui_file_list_t *)
691 * @param kbd_event Keyboard event
692 * @return @c ui_claimed iff the event is claimed
693 */
694ui_evclaim_t ui_file_list_ctl_kbd_event(void *arg, kbd_event_t *event)
695{
696 ui_file_list_t *flist = (ui_file_list_t *) arg;
697
698 return ui_file_list_kbd_event(flist, event);
699}
700
701/** Handle file list control position event.
702 *
703 * @param arg Argument (ui_file_list_t *)
704 * @param pos_event Position event
705 * @return @c ui_claimed iff the event is claimed
706 */
707ui_evclaim_t ui_file_list_ctl_pos_event(void *arg, pos_event_t *event)
708{
709 ui_file_list_t *flist = (ui_file_list_t *) arg;
710
711 return ui_file_list_pos_event(flist, event);
712}
713
714/** Append new file list entry.
715 *
716 * @param flist File list
717 * @param attr Entry attributes
718 * @return EOK on success or an error code
719 */
720errno_t ui_file_list_entry_append(ui_file_list_t *flist, ui_file_list_entry_attr_t *attr)
721{
722 ui_file_list_entry_t *entry;
723
724 entry = calloc(1, sizeof(ui_file_list_entry_t));
725 if (entry == NULL)
726 return ENOMEM;
727
728 entry->flist = flist;
729 entry->name = str_dup(attr->name);
730 if (entry->name == NULL) {
731 free(entry);
732 return ENOMEM;
733 }
734
735 entry->size = attr->size;
736 entry->isdir = attr->isdir;
737 entry->svc = attr->svc;
738 link_initialize(&entry->lentries);
739 list_append(&entry->lentries, &flist->entries);
740 ++flist->entries_cnt;
741 return EOK;
742}
743
744/** Delete file list entry.
745 *
746 * @param entry File list entry
747 */
748void ui_file_list_entry_delete(ui_file_list_entry_t *entry)
749{
750 if (entry->flist->cursor == entry)
751 entry->flist->cursor = NULL;
752 if (entry->flist->page == entry)
753 entry->flist->page = NULL;
754
755 list_remove(&entry->lentries);
756 --entry->flist->entries_cnt;
757 free((char *) entry->name);
758 free(entry);
759}
760
761/** Clear file list entry list.
762 *
763 * @param flist File list
764 */
765void ui_file_list_clear_entries(ui_file_list_t *flist)
766{
767 ui_file_list_entry_t *entry;
768
769 entry = ui_file_list_first(flist);
770 while (entry != NULL) {
771 ui_file_list_entry_delete(entry);
772 entry = ui_file_list_first(flist);
773 }
774}
775
776/** Read directory into file list entry list.
777 *
778 * @param flist File list
779 * @param dirname Directory path
780 * @return EOK on success or an error code
781 */
782errno_t ui_file_list_read_dir(ui_file_list_t *flist, const char *dirname)
783{
784 DIR *dir;
785 struct dirent *dirent;
786 vfs_stat_t finfo;
787 char newdir[256];
788 char *ndir = NULL;
789 ui_file_list_entry_attr_t attr;
790 ui_file_list_entry_t *next;
791 ui_file_list_entry_t *prev;
792 char *olddn;
793 size_t pg_size;
794 size_t max_idx;
795 size_t i;
796 errno_t rc;
797
798 rc = vfs_cwd_set(dirname);
799 if (rc != EOK)
800 return rc;
801
802 rc = vfs_cwd_get(newdir, sizeof(newdir));
803 if (rc != EOK)
804 return rc;
805
806 ndir = str_dup(newdir);
807 if (ndir == NULL)
808 return ENOMEM;
809
810 dir = opendir(".");
811 if (dir == NULL) {
812 rc = errno;
813 goto error;
814 }
815
816 if (str_cmp(ndir, "/") != 0) {
817 /* Need to add a synthetic up-dir entry */
818 ui_file_list_entry_attr_init(&attr);
819 attr.name = "..";
820 attr.isdir = true;
821
822 rc = ui_file_list_entry_append(flist, &attr);
823 if (rc != EOK)
824 goto error;
825 }
826
827 dirent = readdir(dir);
828 while (dirent != NULL) {
829 rc = vfs_stat_path(dirent->d_name, &finfo);
830 if (rc != EOK) {
831 /* Possibly a stale entry */
832 dirent = readdir(dir);
833 continue;
834 }
835
836 ui_file_list_entry_attr_init(&attr);
837 attr.name = dirent->d_name;
838 attr.size = finfo.size;
839 attr.isdir = finfo.is_directory;
840 attr.svc = finfo.service;
841
842 rc = ui_file_list_entry_append(flist, &attr);
843 if (rc != EOK)
844 goto error;
845
846 dirent = readdir(dir);
847 }
848
849 closedir(dir);
850
851 rc = ui_file_list_sort(flist);
852 if (rc != EOK)
853 goto error;
854
855 flist->cursor = ui_file_list_first(flist);
856 flist->cursor_idx = 0;
857 flist->page = ui_file_list_first(flist);
858 flist->page_idx = 0;
859
860 /* Moving up? */
861 if (str_cmp(dirname, "..") == 0) {
862 /* Get the last component of old path */
863 olddn = str_rchr(flist->dir, '/');
864 if (olddn != NULL && *olddn != '\0') {
865 /* Find corresponding entry */
866 ++olddn;
867 next = ui_file_list_next(flist->cursor);
868 while (next != NULL && str_cmp(next->name, olddn) <= 0 &&
869 next->isdir) {
870 flist->cursor = next;
871 ++flist->cursor_idx;
872 next = ui_file_list_next(flist->cursor);
873 }
874
875 /* Move page so that cursor is in the center */
876 flist->page = flist->cursor;
877 flist->page_idx = flist->cursor_idx;
878
879 pg_size = ui_file_list_page_size(flist);
880
881 for (i = 0; i < pg_size / 2; i++) {
882 prev = ui_file_list_prev(flist->page);
883 if (prev == NULL)
884 break;
885
886 flist->page = prev;
887 --flist->page_idx;
888 }
889
890 /* Make sure page is not beyond the end if possible */
891 if (flist->entries_cnt > pg_size)
892 max_idx = flist->entries_cnt - pg_size;
893 else
894 max_idx = 0;
895
896 while (flist->page_idx > 0 && flist->page_idx > max_idx) {
897 prev = ui_file_list_prev(flist->page);
898 if (prev == NULL)
899 break;
900
901 flist->page = prev;
902 --flist->page_idx;
903 }
904 }
905 }
906
907 free(flist->dir);
908 flist->dir = ndir;
909
910 return EOK;
911error:
912 (void) vfs_cwd_set(flist->dir);
913 if (ndir != NULL)
914 free(ndir);
915 if (dir != NULL)
916 closedir(dir);
917 return rc;
918}
919
920/** Sort file list entries.
921 *
922 * @param flist File list
923 * @return EOK on success, ENOMEM if out of memory
924 */
925errno_t ui_file_list_sort(ui_file_list_t *flist)
926{
927 ui_file_list_entry_t **emap;
928 ui_file_list_entry_t *entry;
929 size_t i;
930
931 /* Create an array to hold pointer to each entry */
932 emap = calloc(flist->entries_cnt, sizeof(ui_file_list_entry_t *));
933 if (emap == NULL)
934 return ENOMEM;
935
936 /* Write entry pointers to array */
937 entry = ui_file_list_first(flist);
938 i = 0;
939 while (entry != NULL) {
940 assert(i < flist->entries_cnt);
941 emap[i++] = entry;
942 entry = ui_file_list_next(entry);
943 }
944
945 /* Sort the array of pointers */
946 qsort(emap, flist->entries_cnt, sizeof(ui_file_list_entry_t *),
947 ui_file_list_entry_ptr_cmp);
948
949 /* Unlink entries from entry list */
950 entry = ui_file_list_first(flist);
951 while (entry != NULL) {
952 list_remove(&entry->lentries);
953 entry = ui_file_list_first(flist);
954 }
955
956 /* Add entries back to entry list sorted */
957 for (i = 0; i < flist->entries_cnt; i++)
958 list_append(&emap[i]->lentries, &flist->entries);
959
960 free(emap);
961 return EOK;
962}
963
964/** Compare two file list entries indirectly referenced by pointers.
965 *
966 * @param pa Pointer to pointer to first entry
967 * @param pb Pointer to pointer to second entry
968 * @return <0, =0, >=0 if pa < b, pa == pb, pa > pb, resp.
969 */
970int ui_file_list_entry_ptr_cmp(const void *pa, const void *pb)
971{
972 ui_file_list_entry_t *a = *(ui_file_list_entry_t **)pa;
973 ui_file_list_entry_t *b = *(ui_file_list_entry_t **)pb;
974 int dcmp;
975
976 /* Sort directories first */
977 dcmp = b->isdir - a->isdir;
978 if (dcmp != 0)
979 return dcmp;
980
981 return str_cmp(a->name, b->name);
982}
983
984/** Return first file list entry.
985 *
986 * @param flist File list
987 * @return First file list entry or @c NULL if there are no entries
988 */
989ui_file_list_entry_t *ui_file_list_first(ui_file_list_t *flist)
990{
991 link_t *link;
992
993 link = list_first(&flist->entries);
994 if (link == NULL)
995 return NULL;
996
997 return list_get_instance(link, ui_file_list_entry_t, lentries);
998}
999
1000/** Return last file list entry.
1001 *
1002 * @param flist File list
1003 * @return Last file list entry or @c NULL if there are no entries
1004 */
1005ui_file_list_entry_t *ui_file_list_last(ui_file_list_t *flist)
1006{
1007 link_t *link;
1008
1009 link = list_last(&flist->entries);
1010 if (link == NULL)
1011 return NULL;
1012
1013 return list_get_instance(link, ui_file_list_entry_t, lentries);
1014}
1015
1016/** Return next file list entry.
1017 *
1018 * @param cur Current entry
1019 * @return Next entry or @c NULL if @a cur is the last entry
1020 */
1021ui_file_list_entry_t *ui_file_list_next(ui_file_list_entry_t *cur)
1022{
1023 link_t *link;
1024
1025 link = list_next(&cur->lentries, &cur->flist->entries);
1026 if (link == NULL)
1027 return NULL;
1028
1029 return list_get_instance(link, ui_file_list_entry_t, lentries);
1030}
1031
1032/** Return previous file list entry.
1033 *
1034 * @param cur Current entry
1035 * @return Previous entry or @c NULL if @a cur is the first entry
1036 */
1037ui_file_list_entry_t *ui_file_list_prev(ui_file_list_entry_t *cur)
1038{
1039 link_t *link;
1040
1041 link = list_prev(&cur->lentries, &cur->flist->entries);
1042 if (link == NULL)
1043 return NULL;
1044
1045 return list_get_instance(link, ui_file_list_entry_t, lentries);
1046}
1047
1048/** Find the n-th entry of the current file list page.
1049 *
1050 * @param flist File list
1051 * @param n Which entry to get (starting from 0)
1052 * @param ridx Place to store index (within listing) of the entry
1053 * @return n-th entry of the page
1054 */
1055ui_file_list_entry_t *ui_file_list_page_nth_entry(ui_file_list_t *flist,
1056 size_t n, size_t *ridx)
1057{
1058 ui_file_list_entry_t *entry;
1059 size_t i;
1060 size_t idx;
1061
1062 assert(n <= ui_file_list_page_size(flist));
1063
1064 entry = flist->page;
1065 if (entry == NULL)
1066 return NULL;
1067
1068 idx = flist->page_idx;
1069 for (i = 0; i < n; i++) {
1070 entry = ui_file_list_next(entry);
1071 if (entry == NULL)
1072 return NULL;
1073
1074 ++idx;
1075 }
1076
1077 *ridx = idx;
1078 return entry;
1079}
1080
1081/** Get entry under cursor.
1082 *
1083 * @param flist File list
1084 * @return Current cursor
1085 */
1086ui_file_list_entry_t *ui_file_list_get_cursor(ui_file_list_t *flist)
1087{
1088 return flist->cursor;
1089}
1090
1091/** Move cursor to a new position, possibly scrolling.
1092 *
1093 * @param flist File list
1094 * @param entry New entry under cursor
1095 * @param entry_idx Index of new entry under cursor
1096 */
1097void ui_file_list_cursor_move(ui_file_list_t *flist,
1098 ui_file_list_entry_t *entry, size_t entry_idx)
1099{
1100 gfx_context_t *gc = ui_window_get_gc(flist->window);
1101 ui_file_list_entry_t *old_cursor;
1102 size_t old_idx;
1103 size_t rows;
1104 ui_file_list_entry_t *e;
1105 size_t i;
1106
1107 rows = ui_file_list_page_size(flist);
1108
1109 old_cursor = flist->cursor;
1110 old_idx = flist->cursor_idx;
1111
1112 flist->cursor = entry;
1113 flist->cursor_idx = entry_idx;
1114
1115 if (entry_idx >= flist->page_idx &&
1116 entry_idx < flist->page_idx + rows) {
1117 /*
1118 * If cursor is still on the current page, we're not
1119 * scrolling. Just unpaint old cursor and paint new
1120 * cursor.
1121 */
1122 ui_file_list_entry_paint(old_cursor, old_idx);
1123 ui_file_list_entry_paint(flist->cursor, flist->cursor_idx);
1124
1125 (void) gfx_update(gc);
1126 } else {
1127 /*
1128 * Need to scroll and update all rows.
1129 */
1130
1131 /* Scrolling up */
1132 if (entry_idx < flist->page_idx) {
1133 flist->page = entry;
1134 flist->page_idx = entry_idx;
1135 }
1136
1137 /* Scrolling down */
1138 if (entry_idx >= flist->page_idx + rows) {
1139 if (entry_idx >= rows) {
1140 flist->page_idx = entry_idx - rows + 1;
1141 /* Find first page entry (go back rows - 1) */
1142 e = entry;
1143 for (i = 0; i < rows - 1; i++) {
1144 e = ui_file_list_prev(e);
1145 }
1146
1147 /* Should be valid */
1148 assert(e != NULL);
1149 flist->page = e;
1150 } else {
1151 flist->page = ui_file_list_first(flist);
1152 flist->page_idx = 0;
1153 }
1154 }
1155
1156 ui_file_list_scrollbar_update(flist);
1157 (void) ui_file_list_paint(flist);
1158 }
1159}
1160
1161/** Move cursor one entry up.
1162 *
1163 * @param flist File list
1164 */
1165void ui_file_list_cursor_up(ui_file_list_t *flist)
1166{
1167 ui_file_list_entry_t *prev;
1168 size_t prev_idx;
1169
1170 prev = ui_file_list_prev(flist->cursor);
1171 prev_idx = flist->cursor_idx - 1;
1172 if (prev != NULL)
1173 ui_file_list_cursor_move(flist, prev, prev_idx);
1174}
1175
1176/** Move cursor one entry down.
1177 *
1178 * @param flist File list
1179 */
1180void ui_file_list_cursor_down(ui_file_list_t *flist)
1181{
1182 ui_file_list_entry_t *next;
1183 size_t next_idx;
1184
1185 next = ui_file_list_next(flist->cursor);
1186 next_idx = flist->cursor_idx + 1;
1187 if (next != NULL)
1188 ui_file_list_cursor_move(flist, next, next_idx);
1189}
1190
1191/** Move cursor to top.
1192 *
1193 * @param flist File list
1194 */
1195void ui_file_list_cursor_top(ui_file_list_t *flist)
1196{
1197 ui_file_list_cursor_move(flist, ui_file_list_first(flist), 0);
1198}
1199
1200/** Move cursor to bottom.
1201 *
1202 * @param flist File list
1203 */
1204void ui_file_list_cursor_bottom(ui_file_list_t *flist)
1205{
1206 ui_file_list_cursor_move(flist, ui_file_list_last(flist),
1207 flist->entries_cnt - 1);
1208}
1209
1210/** Move cursor one page up.
1211 *
1212 * @param flist File list
1213 */
1214void ui_file_list_page_up(ui_file_list_t *flist)
1215{
1216 gfx_context_t *gc = ui_window_get_gc(flist->window);
1217 ui_file_list_entry_t *old_page;
1218 ui_file_list_entry_t *old_cursor;
1219 size_t old_idx;
1220 size_t rows;
1221 ui_file_list_entry_t *entry;
1222 size_t i;
1223
1224 rows = ui_file_list_page_size(flist);
1225
1226 old_page = flist->page;
1227 old_cursor = flist->cursor;
1228 old_idx = flist->cursor_idx;
1229
1230 /* Move page by rows entries up (if possible) */
1231 for (i = 0; i < rows; i++) {
1232 entry = ui_file_list_prev(flist->page);
1233 if (entry != NULL) {
1234 flist->page = entry;
1235 --flist->page_idx;
1236 }
1237 }
1238
1239 /* Move cursor by rows entries up (if possible) */
1240
1241 for (i = 0; i < rows; i++) {
1242 entry = ui_file_list_prev(flist->cursor);
1243 if (entry != NULL) {
1244 flist->cursor = entry;
1245 --flist->cursor_idx;
1246 }
1247 }
1248
1249 if (flist->page != old_page) {
1250 /* We have scrolled. Need to repaint all entries */
1251 ui_file_list_scrollbar_update(flist);
1252 (void) ui_file_list_paint(flist);
1253 } else if (flist->cursor != old_cursor) {
1254 /* No scrolling, but cursor has moved */
1255 ui_file_list_entry_paint(old_cursor, old_idx);
1256 ui_file_list_entry_paint(flist->cursor, flist->cursor_idx);
1257
1258 (void) gfx_update(gc);
1259 }
1260}
1261
1262/** Move cursor one page down.
1263 *
1264 * @param flist File list
1265 */
1266void ui_file_list_page_down(ui_file_list_t *flist)
1267{
1268 gfx_context_t *gc = ui_window_get_gc(flist->window);
1269 ui_file_list_entry_t *old_page;
1270 ui_file_list_entry_t *old_cursor;
1271 size_t old_idx;
1272 size_t max_idx;
1273 size_t rows;
1274 ui_file_list_entry_t *entry;
1275 size_t i;
1276
1277 rows = ui_file_list_page_size(flist);
1278
1279 old_page = flist->page;
1280 old_cursor = flist->cursor;
1281 old_idx = flist->cursor_idx;
1282
1283 if (flist->entries_cnt > rows)
1284 max_idx = flist->entries_cnt - rows;
1285 else
1286 max_idx = 0;
1287
1288 /* Move page by rows entries down (if possible) */
1289 for (i = 0; i < rows; i++) {
1290 entry = ui_file_list_next(flist->page);
1291 /* Do not scroll that results in a short page */
1292 if (entry != NULL && flist->page_idx < max_idx) {
1293 flist->page = entry;
1294 ++flist->page_idx;
1295 }
1296 }
1297
1298 /* Move cursor by rows entries down (if possible) */
1299
1300 for (i = 0; i < rows; i++) {
1301 entry = ui_file_list_next(flist->cursor);
1302 if (entry != NULL) {
1303 flist->cursor = entry;
1304 ++flist->cursor_idx;
1305 }
1306 }
1307
1308 if (flist->page != old_page) {
1309 /* We have scrolled. Need to repaint all entries */
1310 ui_file_list_scrollbar_update(flist);
1311 (void) ui_file_list_paint(flist);
1312 } else if (flist->cursor != old_cursor) {
1313 /* No scrolling, but cursor has moved */
1314 ui_file_list_entry_paint(old_cursor, old_idx);
1315 ui_file_list_entry_paint(flist->cursor, flist->cursor_idx);
1316
1317 (void) gfx_update(gc);
1318 }
1319}
1320
1321/** Scroll one entry up.
1322 *
1323 * @param flist File list
1324 */
1325void ui_file_list_scroll_up(ui_file_list_t *flist)
1326{
1327 ui_file_list_entry_t *prev;
1328
1329 prev = ui_file_list_prev(flist->page);
1330 if (prev == NULL)
1331 return;
1332
1333 flist->page = prev;
1334 assert(flist->page_idx > 0);
1335 --flist->page_idx;
1336
1337 ui_file_list_scrollbar_update(flist);
1338 (void) ui_file_list_paint(flist);
1339}
1340
1341/** Scroll one entry down.
1342 *
1343 * @param flist File list
1344 */
1345void ui_file_list_scroll_down(ui_file_list_t *flist)
1346{
1347 ui_file_list_entry_t *next;
1348 ui_file_list_entry_t *pgend;
1349 size_t i;
1350 size_t rows;
1351
1352 next = ui_file_list_next(flist->page);
1353 if (next == NULL)
1354 return;
1355
1356 rows = ui_file_list_page_size(flist);
1357
1358 /* Find last page entry */
1359 pgend = flist->page;
1360 for (i = 0; i < rows && pgend != NULL; i++) {
1361 pgend = ui_file_list_next(pgend);
1362 }
1363
1364 /* Scroll down by one entry, if the page remains full */
1365 if (pgend != NULL) {
1366 flist->page = next;
1367 ++flist->page_idx;
1368 }
1369
1370 ui_file_list_scrollbar_update(flist);
1371 (void) ui_file_list_paint(flist);
1372}
1373
1374/** Scroll one page up.
1375 *
1376 * @param flist File list
1377 */
1378void ui_file_list_scroll_page_up(ui_file_list_t *flist)
1379{
1380 ui_file_list_entry_t *prev;
1381 size_t i;
1382 size_t rows;
1383
1384 prev = ui_file_list_prev(flist->page);
1385 if (prev == NULL)
1386 return;
1387
1388 rows = ui_file_list_page_size(flist);
1389
1390 for (i = 0; i < rows && prev != NULL; i++) {
1391 flist->page = prev;
1392 assert(flist->page_idx > 0);
1393 --flist->page_idx;
1394 prev = ui_file_list_prev(prev);
1395 }
1396
1397 ui_file_list_scrollbar_update(flist);
1398 (void) ui_file_list_paint(flist);
1399}
1400
1401/** Scroll one page down.
1402 *
1403 * @param flist File list
1404 */
1405void ui_file_list_scroll_page_down(ui_file_list_t *flist)
1406{
1407 ui_file_list_entry_t *next;
1408 ui_file_list_entry_t *pgend;
1409 size_t i;
1410 size_t rows;
1411
1412 next = ui_file_list_next(flist->page);
1413 if (next == NULL)
1414 return;
1415
1416 rows = ui_file_list_page_size(flist);
1417
1418 /* Find last page entry */
1419 pgend = flist->page;
1420 for (i = 0; i < rows && pgend != NULL; i++) {
1421 pgend = ui_file_list_next(pgend);
1422 }
1423
1424 /* Scroll by up to 'rows' entries, keeping the page full */
1425 for (i = 0; i < rows && pgend != NULL; i++) {
1426 flist->page = next;
1427 ++flist->page_idx;
1428 next = ui_file_list_next(next);
1429 pgend = ui_file_list_next(pgend);
1430 }
1431
1432 ui_file_list_scrollbar_update(flist);
1433 (void) ui_file_list_paint(flist);
1434}
1435
1436/** Scroll to a specific entry
1437 *
1438 * @param flist File list
1439 * @param page_idx New index of first entry on the page
1440 */
1441void ui_file_list_scroll_pos(ui_file_list_t *flist, size_t page_idx)
1442{
1443 ui_file_list_entry_t *entry;
1444 size_t i;
1445
1446 entry = ui_file_list_first(flist);
1447 for (i = 0; i < page_idx; i++) {
1448 entry = ui_file_list_next(entry);
1449 assert(entry != NULL);
1450 }
1451
1452 flist->page = entry;
1453 flist->page_idx = page_idx;
1454
1455 (void) ui_file_list_paint(flist);
1456}
1457
1458/** Open file list entry.
1459 *
1460 * Perform Open action on a file list entry (e.g. switch to a subdirectory).
1461 *
1462 * @param flist File list
1463 * @param entry File list entry
1464 *
1465 * @return EOK on success or an error code
1466 */
1467errno_t ui_file_list_open(ui_file_list_t *flist, ui_file_list_entry_t *entry)
1468{
1469 if (entry->isdir)
1470 return ui_file_list_open_dir(flist, entry);
1471 else if (entry->svc == 0)
1472 return ui_file_list_open_file(flist, entry);
1473 else
1474 return EOK;
1475}
1476
1477/** Open file list directory entry.
1478 *
1479 * Perform Open action on a directory entry (i.e. switch to the directory).
1480 *
1481 * @param flist File list
1482 * @param entry File list entry (which is a directory)
1483 *
1484 * @return EOK on success or an error code
1485 */
1486errno_t ui_file_list_open_dir(ui_file_list_t *flist,
1487 ui_file_list_entry_t *entry)
1488{
1489 gfx_context_t *gc = ui_window_get_gc(flist->window);
1490 char *dirname;
1491 errno_t rc;
1492
1493 assert(entry->isdir);
1494
1495 /*
1496 * Need to copy out name before we free the entry below
1497 * via ui_file_list_clear_entries().
1498 */
1499 dirname = str_dup(entry->name);
1500 if (dirname == NULL)
1501 return ENOMEM;
1502
1503 ui_file_list_clear_entries(flist);
1504
1505 rc = ui_file_list_read_dir(flist, dirname);
1506 if (rc != EOK) {
1507 free(dirname);
1508 return rc;
1509 }
1510
1511 free(dirname);
1512
1513 rc = ui_file_list_paint(flist);
1514 if (rc != EOK)
1515 return rc;
1516
1517 return gfx_update(gc);
1518}
1519
1520/** Open file list file entry.
1521 *
1522 * Perform Open action on a file entry (i.e. try running it).
1523 *
1524 * @param flist File list
1525 * @param entry File list entry (which is a file)
1526 *
1527 * @return EOK on success or an error code
1528 */
1529errno_t ui_file_list_open_file(ui_file_list_t *flist,
1530 ui_file_list_entry_t *entry)
1531{
1532 ui_file_list_selected(flist, entry->name);
1533 return EOK;
1534}
1535
1536/** Request file list activation.
1537 *
1538 * Call back to request file list activation.
1539 *
1540 * @param flist File list
1541 */
1542void ui_file_list_activate_req(ui_file_list_t *flist)
1543{
1544 if (flist->cb != NULL && flist->cb->activate_req != NULL)
1545 flist->cb->activate_req(flist, flist->cb_arg);
1546}
1547
1548/** Call back when a file is selected.
1549 *
1550 * @param flist File list
1551 * @param fname File name
1552 */
1553void ui_file_list_selected(ui_file_list_t *flist, const char *fname)
1554{
1555 if (flist->cb != NULL && flist->cb->selected != NULL)
1556 flist->cb->selected(flist, flist->cb_arg, fname);
1557}
1558
1559/** File list scrollbar up button pressed.
1560 *
1561 * @param scrollbar Scrollbar
1562 * @param arg Argument (ui_file_list_t *)
1563 */
1564static void ui_file_list_scrollbar_up(ui_scrollbar_t *scrollbar, void *arg)
1565{
1566 ui_file_list_t *flist = (ui_file_list_t *)arg;
1567 ui_file_list_scroll_up(flist);
1568}
1569
1570/** File list scrollbar down button pressed.
1571 *
1572 * @param scrollbar Scrollbar
1573 * @param arg Argument (ui_file_list_t *)
1574 */
1575static void ui_file_list_scrollbar_down(ui_scrollbar_t *scrollbar, void *arg)
1576{
1577 ui_file_list_t *flist = (ui_file_list_t *)arg;
1578 ui_file_list_scroll_down(flist);
1579}
1580
1581/** File list scrollbar page up pressed.
1582 *
1583 * @param scrollbar Scrollbar
1584 * @param arg Argument (ui_file_list_t *)
1585 */
1586static void ui_file_list_scrollbar_page_up(ui_scrollbar_t *scrollbar, void *arg)
1587{
1588 ui_file_list_t *flist = (ui_file_list_t *)arg;
1589 ui_file_list_scroll_page_up(flist);
1590}
1591
1592/** File list scrollbar page down pressed.
1593 *
1594 * @param scrollbar Scrollbar
1595 * @param arg Argument (ui_file_list_t *)
1596 */
1597static void ui_file_list_scrollbar_page_down(ui_scrollbar_t *scrollbar,
1598 void *arg)
1599{
1600 ui_file_list_t *flist = (ui_file_list_t *)arg;
1601 ui_file_list_scroll_page_down(flist);
1602}
1603
1604/** File list scrollbar moved.
1605 *
1606 * @param scrollbar Scrollbar
1607 * @param arg Argument (ui_file_list_t *)
1608 */
1609static void ui_file_list_scrollbar_moved(ui_scrollbar_t *scrollbar, void *arg,
1610 gfx_coord_t pos)
1611{
1612 ui_file_list_t *flist = (ui_file_list_t *)arg;
1613 size_t entries;
1614 size_t pglen;
1615 size_t sbar_len;
1616 size_t pgstart;
1617
1618 entries = list_count(&flist->entries);
1619 pglen = ui_file_list_page_size(flist);
1620 sbar_len = ui_scrollbar_move_length(flist->scrollbar);
1621
1622 if (entries > pglen)
1623 pgstart = (entries - pglen) * pos / (sbar_len - 1);
1624 else
1625 pgstart = 0;
1626
1627 ui_file_list_scroll_pos(flist, pgstart);
1628}
1629
1630/** @}
1631 */
Note: See TracBrowser for help on using the repository browser.