Changeset 7cf5ddb in mainline for uspace/lib/ui/src/filelist.c
- Timestamp:
- 2023-03-08T18:21:22Z (2 years ago)
- Branches:
- master, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 42c2e65, 72ac106
- Parents:
- bea6233
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/ui/src/filelist.c
rbea6233 r7cf5ddb 1 1 /* 2 * Copyright (c) 202 2Jiri Svoboda2 * Copyright (c) 2023 Jiri Svoboda 3 3 * All rights reserved. 4 4 * … … 30 30 * @{ 31 31 */ 32 /** @file File list .32 /** @file File list control. 33 33 * 34 34 * Displays a file listing. … … 37 37 #include <dirent.h> 38 38 #include <errno.h> 39 #include <gfx/render.h>40 #include <gfx/text.h>41 39 #include <stdlib.h> 42 40 #include <str.h> 43 41 #include <ui/control.h> 44 42 #include <ui/filelist.h> 45 #include <ui/ paint.h>43 #include <ui/list.h> 46 44 #include <ui/resource.h> 47 #include <ui/scrollbar.h>48 45 #include <vfs/vfs.h> 49 46 #include <qsort.h> … … 56 53 static ui_evclaim_t ui_file_list_ctl_pos_event(void *, pos_event_t *); 57 54 58 /** File list control ops */55 /** List control ops */ 59 56 ui_control_ops_t ui_file_list_ctl_ops = { 60 57 .destroy = ui_file_list_ctl_destroy, … … 64 61 }; 65 62 66 enum { 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 73 static void ui_file_list_scrollbar_up(ui_scrollbar_t *, void *); 74 static void ui_file_list_scrollbar_down(ui_scrollbar_t *, void *); 75 static void ui_file_list_scrollbar_page_up(ui_scrollbar_t *, void *); 76 static void ui_file_list_scrollbar_page_down(ui_scrollbar_t *, void *); 77 static void ui_file_list_scrollbar_moved(ui_scrollbar_t *, void *, gfx_coord_t); 78 79 /** File list scrollbar callbacks */ 80 static 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 63 static void ui_file_list_list_activate_req(ui_list_t *, void *); 64 static void ui_file_list_list_selected(ui_list_entry_t *, void *); 65 66 /** List callbacks */ 67 ui_list_cb_t ui_file_list_list_cb = { 68 .activate_req = ui_file_list_list_activate_req, 69 .selected = ui_file_list_list_selected, 70 .compare = ui_file_list_list_compare, 86 71 }; 87 72 … … 105 90 rc = ui_control_new(&ui_file_list_ctl_ops, (void *)flist, 106 91 &flist->control); 107 if (rc != EOK) { 108 free(flist); 109 return rc; 110 } 92 if (rc != EOK) 93 goto error; 111 94 112 95 rc = gfx_color_new_ega(0x0f, &flist->dir_color); … … 118 101 goto error; 119 102 120 rc = ui_scrollbar_create(ui_window_get_ui(window), window, 121 ui_sbd_vert, &flist->scrollbar); 103 rc = ui_list_create(window, active, &flist->list); 122 104 if (rc != EOK) 123 105 goto error; 124 106 125 ui_scrollbar_set_cb(flist->scrollbar, &ui_file_list_scrollbar_cb, 126 (void *) flist); 107 ui_list_set_cb(flist->list, &ui_file_list_list_cb, (void *)flist); 127 108 128 109 flist->window = window; 129 list_initialize(&flist->entries);130 flist->entries_cnt = 0;131 flist->active = active;132 133 110 *rflist = flist; 134 111 return EOK; 135 112 error: 113 ui_control_delete(flist->control); 136 114 if (flist->dir_color != NULL) 137 115 gfx_color_delete(flist->dir_color); 138 116 if (flist->svc_color != NULL) 139 117 gfx_color_delete(flist->svc_color); 118 free(flist); 119 return rc; 120 } 121 122 /** Destroy file list. 123 * 124 * @param flist File list 125 */ 126 void ui_file_list_destroy(ui_file_list_t *flist) 127 { 128 ui_file_list_clear_entries(flist); 129 ui_list_destroy(flist->list); 140 130 ui_control_delete(flist->control); 141 131 free(flist); 142 return rc;143 }144 145 /** Destroy file list.146 *147 * @param flist File list148 */149 void 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 132 } 155 133 … … 166 144 } 167 145 168 /** Get height of file list entry.169 *170 * @param flist File list171 * @return Entry height in pixels172 */173 gfx_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 entry198 * @param entry_idx Entry index (within list of entries)199 * @return EOK on success or an error code200 */201 errno_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 where288 * it should be cut off (and append some sort of overflow289 * 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 directories307 * util a better solution is available. (E.g. a Size308 * 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 list332 */333 errno_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 list382 * @param event Keyboard event383 * @return ui_claimed iff event was claimed384 */385 ui_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 list426 * @param event Position event427 * @return ui_claimed iff event was claimed428 */429 ui_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 else480 ui_file_list_page_up(flist);481 }482 }483 }484 485 return ui_claimed;486 }487 488 146 /** Get base control for file list. 489 147 * … … 503 161 void ui_file_list_set_rect(ui_file_list_t *flist, gfx_rect_t *rect) 504 162 { 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 */ 518 unsigned 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 */ 533 void 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 */ 561 void 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 */ 589 gfx_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 */ 609 void 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)); 163 ui_list_set_rect(flist->list, rect); 613 164 } 614 165 … … 620 171 bool ui_file_list_is_active(ui_file_list_t *flist) 621 172 { 622 return flist->active;173 return ui_list_is_active(flist->list); 623 174 } 624 175 … … 639 190 } 640 191 641 flist->active = true; 642 (void) ui_file_list_paint(flist); 643 return EOK; 192 return ui_list_activate(flist->list); 644 193 } 645 194 … … 650 199 void ui_file_list_deactivate(ui_file_list_t *flist) 651 200 { 652 flist->active = false; 653 (void) ui_file_list_paint(flist); 201 ui_list_deactivate(flist->list); 654 202 } 655 203 … … 661 209 { 662 210 memset(attr, 0, sizeof(*attr)); 663 }664 665 /** Destroy file list control.666 *667 * @param arg Argument (ui_file_list_t *)668 */669 void 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 code680 */681 errno_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 event692 * @return @c ui_claimed iff the event is claimed693 */694 ui_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 event705 * @return @c ui_claimed iff the event is claimed706 */707 ui_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 211 } 713 212 … … 721 220 { 722 221 ui_file_list_entry_t *entry; 222 ui_list_entry_attr_t lattr; 223 ui_list_entry_t *lentry; 224 ui_resource_t *res; 225 char *caption; 226 errno_t rc; 227 int rv; 228 229 res = ui_window_get_res(flist->window); 723 230 724 231 entry = calloc(1, sizeof(ui_file_list_entry_t)); … … 736 243 entry->isdir = attr->isdir; 737 244 entry->svc = attr->svc; 738 link_initialize(&entry->lentries); 739 list_append(&entry->lentries, &flist->entries); 740 ++flist->entries_cnt; 245 246 if (attr->isdir && !res->textmode) { 247 rv = asprintf(&caption, "[%s]", attr->name); 248 if (rv < 0) 249 caption = NULL; 250 } else { 251 caption = str_dup(attr->name); 252 } 253 254 if (caption == NULL) { 255 free(entry->name); 256 free(entry); 257 return ENOMEM; 258 } 259 260 lattr.caption = caption; 261 lattr.arg = (void *)entry; 262 lattr.color = NULL; 263 lattr.bgcolor = NULL; 264 265 if (res->textmode) { 266 if (attr->isdir) { 267 lattr.color = flist->dir_color; 268 lattr.bgcolor = flist->dir_color; 269 } else if (attr->svc != 0) { 270 lattr.color = flist->svc_color; 271 lattr.bgcolor = flist->svc_color; 272 } 273 } 274 275 rc = ui_list_entry_append(flist->list, &lattr, &lentry); 276 if (rc != EOK) { 277 free(caption); 278 free(entry->name); 279 free(entry); 280 return rc; 281 } 282 283 free(caption); 284 entry->entry = lentry; 741 285 return EOK; 742 286 } … … 748 292 void ui_file_list_entry_delete(ui_file_list_entry_t *entry) 749 293 { 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); 294 ui_list_entry_delete(entry->entry); 295 free(entry->name); 758 296 free(entry); 759 297 } … … 788 326 char *ndir = NULL; 789 327 ui_file_list_entry_attr_t attr; 328 ui_file_list_entry_t *cur; 790 329 ui_file_list_entry_t *next; 791 ui_file_list_entry_t *prev;792 330 char *olddn; 793 size_t pg_size;794 size_t max_idx;795 size_t i;796 331 errno_t rc; 797 332 … … 853 388 goto error; 854 389 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 390 /* Moving up? */ 861 391 if (str_cmp(dirname, "..") == 0) { … … 865 395 /* Find corresponding entry */ 866 396 ++olddn; 867 next = ui_file_list_next(flist->cursor); 397 cur = ui_file_list_first(flist); 398 next = ui_file_list_next(cur); 868 399 while (next != NULL && str_cmp(next->name, olddn) <= 0 && 869 400 next->isdir) { 870 flist->cursor = next; 871 ++flist->cursor_idx; 872 next = ui_file_list_next(flist->cursor); 401 cur = next; 402 next = ui_file_list_next(cur); 873 403 } 874 404 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 } 405 /* Center on the entry */ 406 ui_list_cursor_center(flist->list, cur->entry); 904 407 } 905 408 } … … 925 428 errno_t ui_file_list_sort(ui_file_list_t *flist) 926 429 { 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 */ 970 int 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; 430 return ui_list_sort(flist->list); 431 } 432 433 /** Compare two list entries within file list entries. 434 * 435 * @param ea First UI list entry 436 * @param eb Second UI list entry 437 * @return <0, =0, >=0 if a < b, a == b, a > b, resp. 438 */ 439 int ui_file_list_list_compare(ui_list_entry_t *ea, ui_list_entry_t *eb) 440 { 441 ui_file_list_entry_t *a; 442 ui_file_list_entry_t *b; 974 443 int dcmp; 444 445 a = (ui_file_list_entry_t *)ui_list_entry_get_arg(ea); 446 b = (ui_file_list_entry_t *)ui_list_entry_get_arg(eb); 975 447 976 448 /* Sort directories first */ … … 989 461 ui_file_list_entry_t *ui_file_list_first(ui_file_list_t *flist) 990 462 { 991 link_t *link;992 993 l ink = list_first(&flist->entries);994 if (l ink== NULL)463 ui_list_entry_t *lentry; 464 465 lentry = ui_list_first(flist->list); 466 if (lentry == NULL) 995 467 return NULL; 996 468 997 return list_get_instance(link, ui_file_list_entry_t, lentries);469 return (ui_file_list_entry_t *)ui_list_entry_get_arg(lentry); 998 470 } 999 471 … … 1005 477 ui_file_list_entry_t *ui_file_list_last(ui_file_list_t *flist) 1006 478 { 1007 link_t *link;1008 1009 l ink = list_last(&flist->entries);1010 if (l ink== NULL)479 ui_list_entry_t *lentry; 480 481 lentry = ui_list_last(flist->list); 482 if (lentry == NULL) 1011 483 return NULL; 1012 484 1013 return list_get_instance(link, ui_file_list_entry_t, lentries);485 return (ui_file_list_entry_t *)ui_list_entry_get_arg(lentry); 1014 486 } 1015 487 … … 1021 493 ui_file_list_entry_t *ui_file_list_next(ui_file_list_entry_t *cur) 1022 494 { 1023 link_t *link;1024 1025 l ink = list_next(&cur->lentries, &cur->flist->entries);1026 if (l ink== NULL)495 ui_list_entry_t *lentry; 496 497 lentry = ui_list_next(cur->entry); 498 if (lentry == NULL) 1027 499 return NULL; 1028 500 1029 return list_get_instance(link, ui_file_list_entry_t, lentries);501 return (ui_file_list_entry_t *)ui_list_entry_get_arg(lentry); 1030 502 } 1031 503 … … 1037 509 ui_file_list_entry_t *ui_file_list_prev(ui_file_list_entry_t *cur) 1038 510 { 1039 link_t *link;1040 1041 l ink = list_prev(&cur->lentries, &cur->flist->entries);1042 if (l ink== NULL)511 ui_list_entry_t *lentry; 512 513 lentry = ui_list_prev(cur->entry); 514 if (lentry == NULL) 1043 515 return NULL; 1044 516 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 */ 1055 ui_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; 517 return (ui_file_list_entry_t *)ui_list_entry_get_arg(lentry); 518 } 519 520 /** Get entry under cursor. 521 * 522 * @param flist File list 523 * @return Current cursor 524 */ 525 ui_file_list_entry_t *ui_file_list_get_cursor(ui_file_list_t *flist) 526 { 527 ui_list_entry_t *entry; 528 529 entry = ui_list_get_cursor(flist->list); 1065 530 if (entry == NULL) 1066 531 return NULL; 1067 532 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 */ 1086 ui_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 */ 1097 void 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 */ 1165 void 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 */ 1180 void 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 */ 1195 void 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 */ 1204 void 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 */ 1214 void 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 */ 1266 void 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 */ 1325 void 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 */ 1345 void 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 */ 1378 void 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 */ 1405 void 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 */ 1441 void 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); 533 return (ui_file_list_entry_t *)ui_list_entry_get_arg(entry); 1456 534 } 1457 535 … … 1487 565 ui_file_list_entry_t *entry) 1488 566 { 1489 gfx_context_t *gc = ui_window_get_gc(flist->window);1490 567 char *dirname; 1491 568 errno_t rc; … … 1515 592 return rc; 1516 593 1517 return gfx_update(gc);594 return EOK; 1518 595 } 1519 596 … … 1557 634 } 1558 635 1559 /** File list scrollbar up button pressed. 1560 * 1561 * @param scrollbar Scrollbar 636 /** Paint file list. 637 * 638 * @param flist File list 639 * @return EOK on success or an error code. 640 */ 641 errno_t ui_file_list_paint(ui_file_list_t *flist) 642 { 643 return ui_control_paint(ui_list_ctl(flist->list)); 644 } 645 646 /** Destroy file list control. 647 * 648 * @param arg Argument (ui_list_t *) 649 */ 650 void ui_file_list_ctl_destroy(void *arg) 651 { 652 ui_file_list_t *flist = (ui_file_list_t *) arg; 653 654 ui_file_list_destroy(flist); 655 } 656 657 /** Paint file list control. 658 * 1562 659 * @param arg Argument (ui_file_list_t *) 1563 */ 1564 static void ui_file_list_scrollbar_up(ui_scrollbar_t *scrollbar, void *arg) 660 * @return EOK on success or an error code 661 */ 662 errno_t ui_file_list_ctl_paint(void *arg) 663 { 664 ui_file_list_t *flist = (ui_file_list_t *) arg; 665 666 return ui_file_list_paint(flist); 667 } 668 669 /** Handle file list control keyboard event. 670 * 671 * @param arg Argument (ui_file_list_t *) 672 * @param kbd_event Keyboard event 673 * @return @c ui_claimed iff the event is claimed 674 */ 675 ui_evclaim_t ui_file_list_ctl_kbd_event(void *arg, kbd_event_t *event) 676 { 677 ui_file_list_t *flist = (ui_file_list_t *) arg; 678 679 return ui_control_kbd_event(ui_list_ctl(flist->list), event); 680 } 681 682 /** Handle file list control position event. 683 * 684 * @param arg Argument (ui_file_list_t *) 685 * @param pos_event Position event 686 * @return @c ui_claimed iff the event is claimed 687 */ 688 ui_evclaim_t ui_file_list_ctl_pos_event(void *arg, pos_event_t *event) 689 { 690 ui_file_list_t *flist = (ui_file_list_t *) arg; 691 692 return ui_control_pos_event(ui_list_ctl(flist->list), event); 693 } 694 695 /** Activate request callback handler for UI list within file list. 696 * 697 * @param list UI list 698 * @param arg Argument (File list) 699 */ 700 static void ui_file_list_list_activate_req(ui_list_t *list, void *arg) 1565 701 { 1566 702 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 */ 1575 static 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 */ 1586 static 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 */ 1597 static 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 */ 1609 static 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); 703 704 ui_file_list_activate_req(flist); 705 } 706 707 /** Entry selected callback handler for UI list within file list. 708 * 709 * @param entr Activated UI list entry 710 * @param arg Argument (File list entry) 711 */ 712 static void ui_file_list_list_selected(ui_list_entry_t *entry, void *arg) 713 { 714 ui_file_list_entry_t *fentry = (void *)arg; 715 716 (void) ui_file_list_open(fentry->flist, fentry); 1628 717 } 1629 718
Note:
See TracChangeset
for help on using the changeset viewer.