Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset 54ddb59 in mainline


Ignore:
Timestamp:
2022-06-20T13:10:08Z (2 weeks ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
master
Children:
52214a2
Parents:
453f9645
git-author:
Jiri Svoboda <jiri@…> (2022-06-19 18:09:49)
git-committer:
Jiri Svoboda <jiri@…> (2022-06-20 13:10:08)
Message:

Base navigator panel on UI file list

Free scrollbar!

Location:
uspace
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/nav/nav.c

    r453f9645 r54ddb59  
    11/*
    2  * Copyright (c) 2021 Jiri Svoboda
     2 * Copyright (c) 2022 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    4040#include <str.h>
    4141#include <ui/fixed.h>
     42#include <ui/filelist.h>
    4243#include <ui/resource.h>
    4344#include <ui/ui.h>
     
    314315
    315316        panel = navigator_get_active_panel(navigator);
    316         panel_open(panel, panel->cursor);
     317        ui_file_list_open(panel->flist, ui_file_list_get_cursor(panel->flist));
    317318}
    318319
  • uspace/app/nav/panel.c

    r453f9645 r54ddb59  
    11/*
    2  * Copyright (c) 2021 Jiri Svoboda
     2 * Copyright (c) 2022 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    3535 */
    3636
    37 #include <dirent.h>
    3837#include <errno.h>
    3938#include <gfx/render.h>
    4039#include <gfx/text.h>
    4140#include <stdlib.h>
    42 #include <str.h>
    4341#include <task.h>
    4442#include <ui/control.h>
     43#include <ui/filelist.h>
    4544#include <ui/paint.h>
    4645#include <ui/resource.h>
    47 #include <vfs/vfs.h>
    48 #include <qsort.h>
    4946#include "panel.h"
    5047#include "nav.h"
     
    5653
    5754/** Panel control ops */
    58 ui_control_ops_t panel_ctl_ops = {
     55static ui_control_ops_t panel_ctl_ops = {
    5956        .destroy = panel_ctl_destroy,
    6057        .paint = panel_ctl_paint,
     
    6360};
    6461
     62static void panel_flist_selected(ui_file_list_t *, void *, const char *);
     63
     64/** Panel file list callbacks */
     65static ui_file_list_cb_t panel_flist_cb = {
     66        .selected = panel_flist_selected
     67};
     68
    6569/** Create panel.
    6670 *
     
    9094                goto error;
    9195
    92         rc = gfx_color_new_ega(0x30, &panel->curs_color);
     96        rc = gfx_color_new_ega(0x0f, &panel->act_border_color);
    9397        if (rc != EOK)
    9498                goto error;
    9599
    96         rc = gfx_color_new_ega(0x0f, &panel->act_border_color);
     100        rc = ui_file_list_create(window, active, &panel->flist);
    97101        if (rc != EOK)
    98102                goto error;
    99103
    100         rc = gfx_color_new_ega(0x0f, &panel->dir_color);
    101         if (rc != EOK)
    102                 goto error;
    103 
    104         rc = gfx_color_new_ega(0x0a, &panel->svc_color);
    105         if (rc != EOK)
    106                 goto error;
     104        ui_file_list_set_cb(panel->flist, &panel_flist_cb, (void *)panel);
    107105
    108106        panel->window = window;
    109         list_initialize(&panel->entries);
    110         panel->entries_cnt = 0;
    111107        panel->active = active;
    112108        *rpanel = panel;
     
    115111        if (panel->color != NULL)
    116112                gfx_color_delete(panel->color);
    117         if (panel->curs_color != NULL)
    118                 gfx_color_delete(panel->curs_color);
    119113        if (panel->act_border_color != NULL)
    120114                gfx_color_delete(panel->act_border_color);
    121         if (panel->dir_color != NULL)
    122                 gfx_color_delete(panel->dir_color);
    123         if (panel->svc_color != NULL)
    124                 gfx_color_delete(panel->svc_color);
     115        if (panel->flist != NULL)
     116                ui_file_list_destroy(panel->flist);
    125117        ui_control_delete(panel->control);
    126118        free(panel);
     
    135127{
    136128        gfx_color_delete(panel->color);
    137         gfx_color_delete(panel->curs_color);
    138129        gfx_color_delete(panel->act_border_color);
    139         gfx_color_delete(panel->dir_color);
    140         gfx_color_delete(panel->svc_color);
    141         panel_clear_entries(panel);
    142130        ui_control_delete(panel->control);
    143131        free(panel);
     
    156144}
    157145
    158 /** Paint panel entry.
    159  *
    160  * @param entry Panel entry
    161  * @param entry_idx Entry index (within list of entries)
    162  * @return EOK on success or an error code
    163  */
    164 errno_t panel_entry_paint(panel_entry_t *entry, size_t entry_idx)
    165 {
    166         panel_t *panel = entry->panel;
     146/** Paint panel.
     147 *
     148 * @param panel Panel
     149 */
     150errno_t panel_paint(panel_t *panel)
     151{
    167152        gfx_context_t *gc = ui_window_get_gc(panel->window);
    168153        ui_resource_t *res = ui_window_get_res(panel->window);
    169         gfx_font_t *font = ui_resource_get_font(res);
    170         gfx_text_fmt_t fmt;
    171         gfx_coord2_t pos;
    172         gfx_rect_t rect;
    173         size_t rows;
    174         errno_t rc;
    175 
    176         gfx_text_fmt_init(&fmt);
    177         fmt.font = font;
    178         rows = panel_page_size(panel);
    179 
    180         /* Do not display entry outside of current page */
    181         if (entry_idx < panel->page_idx ||
    182             entry_idx >= panel->page_idx + rows)
    183                 return EOK;
    184 
    185         pos.x = panel->rect.p0.x + 1;
    186         pos.y = panel->rect.p0.y + 1 + entry_idx - panel->page_idx;
    187 
    188         if (entry == panel->cursor && panel->active)
    189                 fmt.color = panel->curs_color;
    190         else if (entry->isdir)
    191                 fmt.color = panel->dir_color;
    192         else if (entry->svc != 0)
    193                 fmt.color = panel->svc_color;
    194         else
    195                 fmt.color = panel->color;
    196 
    197         /* Draw entry background */
    198         rect.p0 = pos;
    199         rect.p1.x = panel->rect.p1.x - 1;
    200         rect.p1.y = rect.p0.y + 1;
    201 
    202         rc = gfx_set_color(gc, fmt.color);
    203         if (rc != EOK)
    204                 return rc;
    205 
    206         rc = gfx_fill_rect(gc, &rect);
    207         if (rc != EOK)
    208                 return rc;
    209 
    210         /*
    211          * Make sure name does not overflow the entry rectangle.
    212          *
    213          * XXX We probably want to measure the text width, and,
    214          * if it's too long, use gfx_text_find_pos() to find where
    215          * it should be cut off (and append some sort of overflow
    216          * marker.
    217          */
    218         rc = gfx_set_clip_rect(gc, &rect);
    219         if (rc != EOK)
    220                 return rc;
    221 
    222         rc = gfx_puttext(&pos, &fmt, entry->name);
    223         if (rc != EOK) {
    224                 (void) gfx_set_clip_rect(gc, NULL);
    225                 return rc;
    226         }
    227 
    228         return gfx_set_clip_rect(gc, NULL);
    229 }
    230 
    231 /** Paint panel.
    232  *
    233  * @param panel Panel
    234  */
    235 errno_t panel_paint(panel_t *panel)
    236 {
    237         gfx_context_t *gc = ui_window_get_gc(panel->window);
    238         ui_resource_t *res = ui_window_get_res(panel->window);
    239         panel_entry_t *entry;
    240154        ui_box_style_t bstyle;
    241155        gfx_color_t *bcolor;
    242         int i, lines;
     156        ui_control_t *ctl;
    243157        errno_t rc;
    244158
     
    263177                return rc;
    264178
    265         lines = panel_page_size(panel);
    266         i = 0;
    267 
    268         entry = panel->page;
    269         while (entry != NULL && i < lines) {
    270                 rc = panel_entry_paint(entry, panel->page_idx + i);
    271                 if (rc != EOK)
    272                         return rc;
    273 
    274                 ++i;
    275                 entry = panel_next(entry);
    276         }
     179        ctl = ui_file_list_ctl(panel->flist);
     180        rc = ui_control_paint(ctl);
     181        if (rc != EOK)
     182                return rc;
    277183
    278184        rc = gfx_update(gc);
     
    291197ui_evclaim_t panel_kbd_event(panel_t *panel, kbd_event_t *event)
    292198{
     199        ui_control_t *ctl;
     200
    293201        if (!panel->active)
    294202                return ui_unclaimed;
    295203
    296         if (event->type == KEY_PRESS) {
    297                 if ((event->mods & (KM_CTRL | KM_ALT | KM_SHIFT)) == 0) {
    298                         switch (event->key) {
    299                         case KC_UP:
    300                                 panel_cursor_up(panel);
    301                                 break;
    302                         case KC_DOWN:
    303                                 panel_cursor_down(panel);
    304                                 break;
    305                         case KC_HOME:
    306                                 panel_cursor_top(panel);
    307                                 break;
    308                         case KC_END:
    309                                 panel_cursor_bottom(panel);
    310                                 break;
    311                         case KC_PAGE_UP:
    312                                 panel_page_up(panel);
    313                                 break;
    314                         case KC_PAGE_DOWN:
    315                                 panel_page_down(panel);
    316                                 break;
    317                         case KC_ENTER:
    318                                 panel_open(panel, panel->cursor);
    319                                 break;
    320                         default:
    321                                 break;
    322                         }
    323                 }
    324         }
    325 
    326         return ui_claimed;
     204        ctl = ui_file_list_ctl(panel->flist);
     205        return ui_control_kbd_event(ctl, event);
    327206}
    328207
     
    336215{
    337216        gfx_coord2_t pos;
    338         gfx_rect_t irect;
    339         panel_entry_t *entry;
    340         size_t entry_idx;
    341         int n;
     217        ui_control_t *ctl;
    342218
    343219        pos.x = event->hpos;
     
    349225                panel_activate_req(panel);
    350226
     227        ctl = ui_file_list_ctl(panel->flist);
     228        return ui_control_pos_event(ctl, event);
     229}
     230
     231/** Get base control for panel.
     232 *
     233 * @param panel Panel
     234 * @return Base UI control
     235 */
     236ui_control_t *panel_ctl(panel_t *panel)
     237{
     238        return panel->control;
     239}
     240
     241/** Set panel rectangle.
     242 *
     243 * @param panel Panel
     244 * @param rect Rectangle
     245 */
     246void panel_set_rect(panel_t *panel, gfx_rect_t *rect)
     247{
     248        gfx_rect_t irect;
     249
     250        panel->rect = *rect;
     251
    351252        irect.p0.x = panel->rect.p0.x + 1;
    352253        irect.p0.y = panel->rect.p0.y + 1;
    353         irect.p1.x = panel->rect.p1.x - 1;
     254        irect.p1.x = panel->rect.p1.x;
    354255        irect.p1.y = panel->rect.p1.y - 1;
    355256
    356         if (event->type == POS_PRESS || event->type == POS_DCLICK) {
    357                 /* Did we click on one of the entries? */
    358                 if (gfx_pix_inside_rect(&pos, &irect)) {
    359                         /* Index within page */
    360                         n = pos.y - irect.p0.y;
    361 
    362                         /* Entry and its index within entire listing */
    363                         entry = panel_page_nth_entry(panel, n, &entry_idx);
    364 
    365                         if (event->type == POS_PRESS) {
    366                                 /* Move to the entry found */
    367                                 panel_cursor_move(panel, entry, entry_idx);
    368                         } else {
    369                                 /* event->type == POS_DCLICK */
    370                                 panel_open(panel, entry);
    371                         }
    372                 } else {
    373                         /* It's in the border. */
    374                         if (event->type == POS_PRESS) {
    375                                 /* Top or bottom half? */
    376                                 if (pos.y >= (irect.p0.y + irect.p1.y) / 2)
    377                                         panel_page_down(panel);
    378                                 else
    379                                         panel_page_up(panel);
    380                         }
    381                 }
    382         }
    383 
    384         return ui_claimed;
    385 }
    386 
    387 /** Get base control for panel.
    388  *
    389  * @param panel Panel
    390  * @return Base UI control
    391  */
    392 ui_control_t *panel_ctl(panel_t *panel)
    393 {
    394         return panel->control;
    395 }
    396 
    397 /** Set panel rectangle.
    398  *
    399  * @param panel Panel
    400  * @param rect Rectangle
    401  */
    402 void panel_set_rect(panel_t *panel, gfx_rect_t *rect)
    403 {
    404         panel->rect = *rect;
    405 }
    406 
    407 /** Get panel page size.
    408  *
    409  * @param panel Panel
    410  * @return Number of entries that fit in panel at the same time.
    411  */
    412 unsigned panel_page_size(panel_t *panel)
    413 {
    414         return panel->rect.p1.y - panel->rect.p0.y - 2;
     257        ui_file_list_set_rect(panel->flist, &irect);
    415258}
    416259
     
    435278        errno_t rc;
    436279
    437         if (panel->dir != NULL) {
    438                 rc = vfs_cwd_set(panel->dir);
    439                 if (rc != EOK)
    440                         return rc;
    441         }
     280        rc = ui_file_list_activate(panel->flist);
     281        if (rc != EOK)
     282                return rc;
    442283
    443284        panel->active = true;
     
    452293void panel_deactivate(panel_t *panel)
    453294{
     295        ui_file_list_deactivate(panel->flist);
    454296        panel->active = false;
    455297        (void) panel_paint(panel);
    456 }
    457 
    458 /** Initialize panel entry attributes.
    459  *
    460  * @param attr Attributes
    461  */
    462 void panel_entry_attr_init(panel_entry_attr_t *attr)
    463 {
    464         memset(attr, 0, sizeof(*attr));
    465298}
    466299
     
    514347}
    515348
    516 /** Append new panel entry.
    517  *
    518  * @param panel Panel
    519  * @param attr Entry attributes
    520  * @return EOK on success or an error code
    521  */
    522 errno_t panel_entry_append(panel_t *panel, panel_entry_attr_t *attr)
    523 {
    524         panel_entry_t *entry;
    525 
    526         entry = calloc(1, sizeof(panel_entry_t));
    527         if (entry == NULL)
    528                 return ENOMEM;
    529 
    530         entry->panel = panel;
    531         entry->name = str_dup(attr->name);
    532         if (entry->name == NULL) {
    533                 free(entry);
    534                 return ENOMEM;
    535         }
    536 
    537         entry->size = attr->size;
    538         entry->isdir = attr->isdir;
    539         entry->svc = attr->svc;
    540         link_initialize(&entry->lentries);
    541         list_append(&entry->lentries, &panel->entries);
    542         ++panel->entries_cnt;
    543         return EOK;
    544 }
    545 
    546 /** Delete panel entry.
    547  *
    548  * @param entry Panel entry
    549  */
    550 void panel_entry_delete(panel_entry_t *entry)
    551 {
    552         if (entry->panel->cursor == entry)
    553                 entry->panel->cursor = NULL;
    554         if (entry->panel->page == entry)
    555                 entry->panel->page = NULL;
    556 
    557         list_remove(&entry->lentries);
    558         --entry->panel->entries_cnt;
    559         free((char *) entry->name);
    560         free(entry);
    561 }
    562 
    563 /** Clear panel entry list.
    564  *
    565  * @param panel Panel
    566  */
    567 void panel_clear_entries(panel_t *panel)
    568 {
    569         panel_entry_t *entry;
    570 
    571         entry = panel_first(panel);
    572         while (entry != NULL) {
    573                 panel_entry_delete(entry);
    574                 entry = panel_first(panel);
    575         }
    576 }
    577 
    578349/** Read directory into panel entry list.
    579350 *
     
    584355errno_t panel_read_dir(panel_t *panel, const char *dirname)
    585356{
    586         DIR *dir;
    587         struct dirent *dirent;
    588         vfs_stat_t finfo;
    589         char newdir[256];
    590         char *ndir = NULL;
    591         panel_entry_attr_t attr;
    592         panel_entry_t *next;
    593         panel_entry_t *prev;
    594         char *olddn;
    595         size_t pg_size;
    596         size_t max_idx;
    597         size_t i;
    598         errno_t rc;
    599 
    600         rc = vfs_cwd_set(dirname);
    601         if (rc != EOK)
    602                 return rc;
    603 
    604         rc = vfs_cwd_get(newdir, sizeof(newdir));
    605         if (rc != EOK)
    606                 return rc;
    607 
    608         ndir = str_dup(newdir);
    609         if (ndir == NULL)
    610                 return ENOMEM;
    611 
    612         dir = opendir(".");
    613         if (dir == NULL) {
    614                 rc = errno;
    615                 goto error;
    616         }
    617 
    618         if (str_cmp(ndir, "/") != 0) {
    619                 /* Need to add a synthetic up-dir entry */
    620                 panel_entry_attr_init(&attr);
    621                 attr.name = "..";
    622                 attr.isdir = true;
    623 
    624                 rc = panel_entry_append(panel, &attr);
    625                 if (rc != EOK)
    626                         goto error;
    627         }
    628 
    629         dirent = readdir(dir);
    630         while (dirent != NULL) {
    631                 rc = vfs_stat_path(dirent->d_name, &finfo);
    632                 if (rc != EOK) {
    633                         /* Possibly a stale entry */
    634                         dirent = readdir(dir);
    635                         continue;
    636                 }
    637 
    638                 panel_entry_attr_init(&attr);
    639                 attr.name = dirent->d_name;
    640                 attr.size = finfo.size;
    641                 attr.isdir = finfo.is_directory;
    642                 attr.svc = finfo.service;
    643 
    644                 rc = panel_entry_append(panel, &attr);
    645                 if (rc != EOK)
    646                         goto error;
    647 
    648                 dirent = readdir(dir);
    649         }
    650 
    651         closedir(dir);
    652 
    653         rc = panel_sort(panel);
    654         if (rc != EOK)
    655                 goto error;
    656 
    657         panel->cursor = panel_first(panel);
    658         panel->cursor_idx = 0;
    659         panel->page = panel_first(panel);
    660         panel->page_idx = 0;
    661 
    662         /* Moving up? */
    663         if (str_cmp(dirname, "..") == 0) {
    664                 /* Get the last component of old path */
    665                 olddn = str_rchr(panel->dir, '/');
    666                 if (olddn != NULL && *olddn != '\0') {
    667                         /* Find corresponding entry */
    668                         ++olddn;
    669                         next = panel_next(panel->cursor);
    670                         while (next != NULL && str_cmp(next->name, olddn) <= 0 &&
    671                             next->isdir) {
    672                                 panel->cursor = next;
    673                                 ++panel->cursor_idx;
    674                                 next = panel_next(panel->cursor);
    675                         }
    676 
    677                         /* Move page so that cursor is in the center */
    678                         panel->page = panel->cursor;
    679                         panel->page_idx = panel->cursor_idx;
    680 
    681                         pg_size = panel_page_size(panel);
    682 
    683                         for (i = 0; i < pg_size / 2; i++) {
    684                                 prev = panel_prev(panel->page);
    685                                 if (prev == NULL)
    686                                         break;
    687 
    688                                 panel->page = prev;
    689                                 --panel->page_idx;
    690                         }
    691 
    692                         /* Make sure page is not beyond the end if possible */
    693                         if (panel->entries_cnt > pg_size)
    694                                 max_idx = panel->entries_cnt - pg_size;
    695                         else
    696                                 max_idx = 0;
    697 
    698                         while (panel->page_idx > 0 && panel->page_idx > max_idx) {
    699                                 prev = panel_prev(panel->page);
    700                                 if (prev == NULL)
    701                                         break;
    702 
    703                                 panel->page = prev;
    704                                 --panel->page_idx;
    705                         }
    706                 }
    707         }
    708 
    709         free(panel->dir);
    710         panel->dir = ndir;
    711 
    712         return EOK;
    713 error:
    714         (void) vfs_cwd_set(panel->dir);
    715         if (ndir != NULL)
    716                 free(ndir);
    717         if (dir != NULL)
    718                 closedir(dir);
    719         return rc;
    720 }
    721 
    722 /** Sort panel entries.
    723  *
    724  * @param panel Panel
    725  * @return EOK on success, ENOMEM if out of memory
    726  */
    727 errno_t panel_sort(panel_t *panel)
    728 {
    729         panel_entry_t **emap;
    730         panel_entry_t *entry;
    731         size_t i;
    732 
    733         /* Create an array to hold pointer to each entry */
    734         emap = calloc(panel->entries_cnt, sizeof(panel_entry_t *));
    735         if (emap == NULL)
    736                 return ENOMEM;
    737 
    738         /* Write entry pointers to array */
    739         entry = panel_first(panel);
    740         i = 0;
    741         while (entry != NULL) {
    742                 assert(i < panel->entries_cnt);
    743                 emap[i++] = entry;
    744                 entry = panel_next(entry);
    745         }
    746 
    747         /* Sort the array of pointers */
    748         qsort(emap, panel->entries_cnt, sizeof(panel_entry_t *),
    749             panel_entry_ptr_cmp);
    750 
    751         /* Unlink entries from entry list */
    752         entry = panel_first(panel);
    753         while (entry != NULL) {
    754                 list_remove(&entry->lentries);
    755                 entry = panel_first(panel);
    756         }
    757 
    758         /* Add entries back to entry list sorted */
    759         for (i = 0; i < panel->entries_cnt; i++)
    760                 list_append(&emap[i]->lentries, &panel->entries);
    761 
    762         free(emap);
    763         return EOK;
    764 }
    765 
    766 /** Compare two panel entries indirectly referenced by pointers.
    767  *
    768  * @param pa Pointer to pointer to first entry
    769  * @param pb Pointer to pointer to second entry
    770  * @return <0, =0, >=0 if pa < b, pa == pb, pa > pb, resp.
    771  */
    772 int panel_entry_ptr_cmp(const void *pa, const void *pb)
    773 {
    774         panel_entry_t *a = *(panel_entry_t **)pa;
    775         panel_entry_t *b = *(panel_entry_t **)pb;
    776         int dcmp;
    777 
    778         /* Sort directories first */
    779         dcmp = b->isdir - a->isdir;
    780         if (dcmp != 0)
    781                 return dcmp;
    782 
    783         return str_cmp(a->name, b->name);
    784 }
    785 
    786 /** Return first panel entry.
    787  *
    788  * @panel Panel
    789  * @return First panel entry or @c NULL if there are no entries
    790  */
    791 panel_entry_t *panel_first(panel_t *panel)
    792 {
    793         link_t *link;
    794 
    795         link = list_first(&panel->entries);
    796         if (link == NULL)
    797                 return NULL;
    798 
    799         return list_get_instance(link, panel_entry_t, lentries);
    800 }
    801 
    802 /** Return last panel entry.
    803  *
    804  * @panel Panel
    805  * @return Last panel entry or @c NULL if there are no entries
    806  */
    807 panel_entry_t *panel_last(panel_t *panel)
    808 {
    809         link_t *link;
    810 
    811         link = list_last(&panel->entries);
    812         if (link == NULL)
    813                 return NULL;
    814 
    815         return list_get_instance(link, panel_entry_t, lentries);
    816 }
    817 
    818 /** Return next panel entry.
    819  *
    820  * @param cur Current entry
    821  * @return Next entry or @c NULL if @a cur is the last entry
    822  */
    823 panel_entry_t *panel_next(panel_entry_t *cur)
    824 {
    825         link_t *link;
    826 
    827         link = list_next(&cur->lentries, &cur->panel->entries);
    828         if (link == NULL)
    829                 return NULL;
    830 
    831         return list_get_instance(link, panel_entry_t, lentries);
    832 }
    833 
    834 /** Return previous panel entry.
    835  *
    836  * @param cur Current entry
    837  * @return Previous entry or @c NULL if @a cur is the first entry
    838  */
    839 panel_entry_t *panel_prev(panel_entry_t *cur)
    840 {
    841         link_t *link;
    842 
    843         link = list_prev(&cur->lentries, &cur->panel->entries);
    844         if (link == NULL)
    845                 return NULL;
    846 
    847         return list_get_instance(link, panel_entry_t, lentries);
    848 }
    849 
    850 /** Find the n-th entry of the current panel page.
    851  *
    852  * If the page is short and has less than n+1 entries, return the last entry.
    853  *
    854  * @param panel Panel
    855  * @param n Which entry to get (starting from 0)
    856  * @param ridx Place to store index (within listing) of the entry
    857  * @return n-th entry of the page
    858  */
    859 panel_entry_t *panel_page_nth_entry(panel_t *panel, size_t n, size_t *ridx)
    860 {
    861         panel_entry_t *entry;
    862         panel_entry_t *next;
    863         size_t i;
    864         size_t idx;
    865 
    866         assert(n < panel_page_size(panel));
    867 
    868         entry = panel->page;
    869         idx = panel->page_idx;
    870         for (i = 0; i < n; i++) {
    871                 next = panel_next(entry);
    872                 if (next == NULL)
    873                         break;
    874 
    875                 entry = next;
    876                 ++idx;
    877         }
    878 
    879         *ridx = idx;
    880         return entry;
    881 }
    882 
    883 /** Move cursor to a new position, possibly scrolling.
    884  *
    885  * @param panel Panel
    886  * @param entry New entry under cursor
    887  * @param entry_idx Index of new entry under cursor
    888  */
    889 void panel_cursor_move(panel_t *panel, panel_entry_t *entry, size_t entry_idx)
    890 {
    891         gfx_context_t *gc = ui_window_get_gc(panel->window);
    892         panel_entry_t *old_cursor;
    893         size_t old_idx;
    894         size_t rows;
    895         panel_entry_t *e;
    896         size_t i;
    897 
    898         rows = panel_page_size(panel);
    899 
    900         old_cursor = panel->cursor;
    901         old_idx = panel->cursor_idx;
    902 
    903         panel->cursor = entry;
    904         panel->cursor_idx = entry_idx;
    905 
    906         if (entry_idx >= panel->page_idx &&
    907             entry_idx < panel->page_idx + rows) {
    908                 /*
    909                  * If cursor is still on the current page, we're not
    910                  * scrolling. Just unpaint old cursor and paint new
    911                  * cursor.
    912                  */
    913                 panel_entry_paint(old_cursor, old_idx);
    914                 panel_entry_paint(panel->cursor, panel->cursor_idx);
    915 
    916                 (void) gfx_update(gc);
    917         } else {
    918                 /*
    919                  * Need to scroll and update all rows.
    920                  */
    921 
    922                 /* Scrolling up */
    923                 if (entry_idx < panel->page_idx) {
    924                         panel->page = entry;
    925                         panel->page_idx = entry_idx;
    926                 }
    927 
    928                 /* Scrolling down */
    929                 if (entry_idx >= panel->page_idx + rows) {
    930                         if (entry_idx >= rows) {
    931                                 panel->page_idx = entry_idx - rows + 1;
    932                                 /* Find first page entry (go back rows - 1) */
    933                                 e = entry;
    934                                 for (i = 0; i < rows - 1; i++) {
    935                                         e = panel_prev(e);
    936                                 }
    937 
    938                                 /* Should be valid */
    939                                 assert(e != NULL);
    940                                 panel->page = e;
    941                         } else {
    942                                 panel->page = panel_first(panel);
    943                                 panel->page_idx = 0;
    944                         }
    945                 }
    946 
    947                 (void) panel_paint(panel);
    948         }
    949 }
    950 
    951 /** Move cursor one entry up.
    952  *
    953  * @param panel Panel
    954  */
    955 void panel_cursor_up(panel_t *panel)
    956 {
    957         panel_entry_t *prev;
    958         size_t prev_idx;
    959 
    960         prev = panel_prev(panel->cursor);
    961         prev_idx = panel->cursor_idx - 1;
    962         if (prev != NULL)
    963                 panel_cursor_move(panel, prev, prev_idx);
    964 }
    965 
    966 /** Move cursor one entry down.
    967  *
    968  * @param panel Panel
    969  */
    970 void panel_cursor_down(panel_t *panel)
    971 {
    972         panel_entry_t *next;
    973         size_t next_idx;
    974 
    975         next = panel_next(panel->cursor);
    976         next_idx = panel->cursor_idx + 1;
    977         if (next != NULL)
    978                 panel_cursor_move(panel, next, next_idx);
    979 }
    980 
    981 /** Move cursor to top.
    982  *
    983  * @param panel Panel
    984  */
    985 void panel_cursor_top(panel_t *panel)
    986 {
    987         panel_cursor_move(panel, panel_first(panel), 0);
    988 }
    989 
    990 /** Move cursor to bottom.
    991  *
    992  * @param panel Panel
    993  */
    994 void panel_cursor_bottom(panel_t *panel)
    995 {
    996         panel_cursor_move(panel, panel_last(panel), panel->entries_cnt - 1);
    997 }
    998 
    999 /** Move one page up.
    1000  *
    1001  * @param panel Panel
    1002  */
    1003 void panel_page_up(panel_t *panel)
    1004 {
    1005         gfx_context_t *gc = ui_window_get_gc(panel->window);
    1006         panel_entry_t *old_page;
    1007         panel_entry_t *old_cursor;
    1008         size_t old_idx;
    1009         size_t rows;
    1010         panel_entry_t *entry;
    1011         size_t i;
    1012 
    1013         rows = panel_page_size(panel);
    1014 
    1015         old_page = panel->page;
    1016         old_cursor = panel->cursor;
    1017         old_idx = panel->cursor_idx;
    1018 
    1019         /* Move page by rows entries up (if possible) */
    1020         for (i = 0; i < rows; i++) {
    1021                 entry = panel_prev(panel->page);
    1022                 if (entry != NULL) {
    1023                         panel->page = entry;
    1024                         --panel->page_idx;
    1025                 }
    1026         }
    1027 
    1028         /* Move cursor by rows entries up (if possible) */
    1029 
    1030         for (i = 0; i < rows; i++) {
    1031                 entry = panel_prev(panel->cursor);
    1032                 if (entry != NULL) {
    1033                         panel->cursor = entry;
    1034                         --panel->cursor_idx;
    1035                 }
    1036         }
    1037 
    1038         if (panel->page != old_page) {
    1039                 /* We have scrolled. Need to repaint all entries */
    1040                 (void) panel_paint(panel);
    1041         } else if (panel->cursor != old_cursor) {
    1042                 /* No scrolling, but cursor has moved */
    1043                 panel_entry_paint(old_cursor, old_idx);
    1044                 panel_entry_paint(panel->cursor, panel->cursor_idx);
    1045 
    1046                 (void) gfx_update(gc);
    1047         }
    1048 }
    1049 
    1050 /** Move one page down.
    1051  *
    1052  * @param panel Panel
    1053  */
    1054 void panel_page_down(panel_t *panel)
    1055 {
    1056         gfx_context_t *gc = ui_window_get_gc(panel->window);
    1057         panel_entry_t *old_page;
    1058         panel_entry_t *old_cursor;
    1059         size_t old_idx;
    1060         size_t max_idx;
    1061         size_t rows;
    1062         panel_entry_t *entry;
    1063         size_t i;
    1064 
    1065         rows = panel_page_size(panel);
    1066 
    1067         old_page = panel->page;
    1068         old_cursor = panel->cursor;
    1069         old_idx = panel->cursor_idx;
    1070 
    1071         if (panel->entries_cnt > rows)
    1072                 max_idx = panel->entries_cnt - rows;
    1073         else
    1074                 max_idx = 0;
    1075 
    1076         /* Move page by rows entries down (if possible) */
    1077         for (i = 0; i < rows; i++) {
    1078                 entry = panel_next(panel->page);
    1079                 /* Do not scroll that results in a short page */
    1080                 if (entry != NULL && panel->page_idx < max_idx) {
    1081                         panel->page = entry;
    1082                         ++panel->page_idx;
    1083                 }
    1084         }
    1085 
    1086         /* Move cursor by rows entries down (if possible) */
    1087 
    1088         for (i = 0; i < rows; i++) {
    1089                 entry = panel_next(panel->cursor);
    1090                 if (entry != NULL) {
    1091                         panel->cursor = entry;
    1092                         ++panel->cursor_idx;
    1093                 }
    1094         }
    1095 
    1096         if (panel->page != old_page) {
    1097                 /* We have scrolled. Need to repaint all entries */
    1098                 (void) panel_paint(panel);
    1099         } else if (panel->cursor != old_cursor) {
    1100                 /* No scrolling, but cursor has moved */
    1101                 panel_entry_paint(old_cursor, old_idx);
    1102                 panel_entry_paint(panel->cursor, panel->cursor_idx);
    1103 
    1104                 (void) gfx_update(gc);
    1105         }
    1106 }
    1107 
    1108 /** Open panel entry.
    1109  *
    1110  * Perform Open action on a panel entry (e.g. switch to a subdirectory).
    1111  *
    1112  * @param panel Panel
    1113  * @param entry Panel entry
     357        return ui_file_list_read_dir(panel->flist, dirname);
     358}
     359
     360/** Request panel activation.
     361 *
     362 * Call back to request panel activation.
     363 *
     364 * @param panel Panel
     365 */
     366void panel_activate_req(panel_t *panel)
     367{
     368        if (panel->cb != NULL && panel->cb->activate_req != NULL)
     369                panel->cb->activate_req(panel->cb_arg, panel);
     370}
     371
     372/** Open panel file entry.
     373 *
     374 * Perform Open action on a file entry (i.e. try running it).
     375 *
     376 * @param panel Panel
     377 * @param fname File name
    1114378 *
    1115379 * @return EOK on success or an error code
    1116380 */
    1117 errno_t panel_open(panel_t *panel, panel_entry_t *entry)
    1118 {
    1119         if (entry->isdir)
    1120                 return panel_open_dir(panel, entry);
    1121         else if (entry->svc == 0)
    1122                 return panel_open_file(panel, entry);
    1123         else
    1124                 return EOK;
    1125 }
    1126 
    1127 /** Open panel directory entry.
    1128  *
    1129  * Perform Open action on a directory entry (i.e. switch to the directory).
    1130  *
    1131  * @param panel Panel
    1132  * @param entry Panel entry (which is a directory)
    1133  *
    1134  * @return EOK on success or an error code
    1135  */
    1136 errno_t panel_open_dir(panel_t *panel, panel_entry_t *entry)
    1137 {
    1138         gfx_context_t *gc = ui_window_get_gc(panel->window);
    1139         char *dirname;
    1140         errno_t rc;
    1141 
    1142         assert(entry->isdir);
    1143 
    1144         /*
    1145          * Need to copy out name before we free the entry below
    1146          * via panel_clear_entries().
    1147          */
    1148         dirname = str_dup(entry->name);
    1149         if (dirname == NULL)
    1150                 return ENOMEM;
    1151 
    1152         panel_clear_entries(panel);
    1153 
    1154         rc = panel_read_dir(panel, dirname);
    1155         if (rc != EOK) {
    1156                 free(dirname);
    1157                 return rc;
    1158         }
    1159 
    1160         free(dirname);
    1161 
    1162         rc = panel_paint(panel);
    1163         if (rc != EOK)
    1164                 return rc;
    1165 
    1166         return gfx_update(gc);
    1167 }
    1168 
    1169 /** Open panel file entry.
    1170  *
    1171  * Perform Open action on a file entry (i.e. try running it).
    1172  *
    1173  * @param panel Panel
    1174  * @param entry Panel entry (which is a file)
    1175  *
    1176  * @return EOK on success or an error code
    1177  */
    1178 errno_t panel_open_file(panel_t *panel, panel_entry_t *entry)
     381static errno_t panel_open_file(panel_t *panel, const char *fname)
    1179382{
    1180383        task_id_t id;
     
    1185388        ui_t *ui;
    1186389
    1187         /* It's not a directory */
    1188         assert(!entry->isdir);
    1189         /* It's not a service-special file */
    1190         assert(entry->svc == 0);
    1191 
    1192390        ui = ui_window_get_ui(panel->window);
    1193391
     
    1197395                return rc;
    1198396
    1199         rc = task_spawnl(&id, &wait, entry->name, entry->name, NULL);
     397        rc = task_spawnl(&id, &wait, fname, fname, NULL);
    1200398        if (rc != EOK)
    1201399                goto error;
     
    1218416}
    1219417
    1220 /** Request panel activation.
    1221  *
    1222  * Call back to request panel activation.
    1223  *
    1224  * @param panel Panel
    1225  */
    1226 void panel_activate_req(panel_t *panel)
    1227 {
    1228         if (panel->cb != NULL && panel->cb->activate_req != NULL)
    1229                 panel->cb->activate_req(panel->cb_arg, panel);
     418/** File in panel file list was selected.
     419 *
     420 * @param flist File list
     421 * @param arg Argument (panel_t *)
     422 * @param fname File name
     423 */
     424static void panel_flist_selected(ui_file_list_t *flist, void *arg,
     425    const char *fname)
     426{
     427        panel_t *panel = (panel_t *)arg;
     428
     429        (void) panel_open_file(panel, fname);
    1230430}
    1231431
  • uspace/app/nav/panel.h

    r453f9645 r54ddb59  
    11/*
    2  * Copyright (c) 2021 Jiri Svoboda
     2 * Copyright (c) 2022 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    4949extern void panel_destroy(panel_t *);
    5050extern void panel_set_cb(panel_t *, panel_cb_t *, void *);
    51 extern errno_t panel_entry_paint(panel_entry_t *, size_t);
    5251extern errno_t panel_paint(panel_t *);
    5352extern ui_evclaim_t panel_kbd_event(panel_t *, kbd_event_t *);
     
    5554extern ui_control_t *panel_ctl(panel_t *);
    5655extern void panel_set_rect(panel_t *, gfx_rect_t *);
    57 extern unsigned panel_page_size(panel_t *);
    5856extern bool panel_is_active(panel_t *);
    5957extern errno_t panel_activate(panel_t *);
    6058extern void panel_deactivate(panel_t *);
    61 extern void panel_entry_attr_init(panel_entry_attr_t *);
    62 extern errno_t panel_entry_append(panel_t *, panel_entry_attr_t *);
    63 extern void panel_entry_delete(panel_entry_t *);
    64 extern void panel_clear_entries(panel_t *);
    6559extern errno_t panel_read_dir(panel_t *, const char *);
    66 extern errno_t panel_sort(panel_t *);
    67 extern int panel_entry_ptr_cmp(const void *, const void *);
    68 extern panel_entry_t *panel_first(panel_t *);
    69 extern panel_entry_t *panel_last(panel_t *);
    70 extern panel_entry_t *panel_next(panel_entry_t *);
    71 extern panel_entry_t *panel_prev(panel_entry_t *);
    72 extern panel_entry_t *panel_page_nth_entry(panel_t *, size_t, size_t *);
    73 extern void panel_cursor_move(panel_t *, panel_entry_t *, size_t);
    74 extern void panel_cursor_up(panel_t *);
    75 extern void panel_cursor_down(panel_t *);
    76 extern void panel_cursor_top(panel_t *);
    77 extern void panel_cursor_bottom(panel_t *);
    78 extern void panel_page_up(panel_t *);
    79 extern void panel_page_down(panel_t *);
    80 extern errno_t panel_open(panel_t *, panel_entry_t *);
    81 extern errno_t panel_open_dir(panel_t *, panel_entry_t *);
    82 extern errno_t panel_open_file(panel_t *, panel_entry_t *);
    8360extern void panel_activate_req(panel_t *);
    8461
  • uspace/app/nav/test/panel.c

    r453f9645 r54ddb59  
    11/*
    2  * Copyright (c) 2021 Jiri Svoboda
     2 * Copyright (c) 2022 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    8181}
    8282
    83 /** Test panel_entry_paint() */
    84 PCUT_TEST(entry_paint)
    85 {
    86         ui_t *ui;
    87         ui_window_t *window;
    88         ui_wnd_params_t params;
    89         panel_t *panel;
    90         panel_entry_attr_t attr;
    91         errno_t rc;
    92 
    93         rc = ui_create_disp(NULL, &ui);
    94         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    95 
    96         ui_wnd_params_init(&params);
    97         params.caption = "Test";
    98 
    99         rc = ui_window_create(ui, &params, &window);
    100         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    101 
    102         rc = panel_create(window, true, &panel);
    103         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    104 
    105         panel_entry_attr_init(&attr);
    106         attr.name = "a";
    107         attr.size = 1;
    108 
    109         rc = panel_entry_append(panel, &attr);
    110         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    111 
    112         rc = panel_entry_paint(panel_first(panel), 0);
    113         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    114 
    115         panel_destroy(panel);
    116         ui_window_destroy(window);
    117         ui_destroy(ui);
    118 }
    119 
    12083/** Test panel_paint() */
    12184PCUT_TEST(paint)
     
    205168PCUT_TEST(pos_event)
    206169{
    207         ui_t *ui;
    208         ui_window_t *window;
    209         ui_wnd_params_t params;
    210         panel_t *panel;
    211         ui_evclaim_t claimed;
    212         pos_event_t event;
    213         gfx_rect_t rect;
    214         panel_entry_attr_t attr;
    215         errno_t rc;
    216 
    217         rc = ui_create_disp(NULL, &ui);
    218         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    219 
    220         ui_wnd_params_init(&params);
    221         params.caption = "Test";
    222 
    223         rc = ui_window_create(ui, &params, &window);
    224         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    225 
    226         rc = panel_create(window, true, &panel);
    227         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    228 
    229         rect.p0.x = 0;
    230         rect.p0.y = 0;
    231         rect.p1.x = 10;
    232         rect.p1.y = 10;
    233         panel_set_rect(panel, &rect);
    234 
    235         panel_entry_attr_init(&attr);
    236         attr.name = "a";
    237         attr.size = 1;
    238         rc = panel_entry_append(panel, &attr);
    239         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    240 
    241         attr.name = "b";
    242         attr.size = 2;
    243         rc = panel_entry_append(panel, &attr);
    244         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    245 
    246         attr.name = "c";
    247         attr.size = 3;
    248         rc = panel_entry_append(panel, &attr);
    249         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    250 
    251         panel->cursor = panel_first(panel);
    252         panel->cursor_idx = 0;
    253         panel->page = panel_first(panel);
    254         panel->page_idx = 0;
    255 
    256         event.pos_id = 0;
    257         event.type = POS_PRESS;
    258         event.btn_num = 1;
    259 
    260         /* Clicking on the middle entry should select it */
    261         event.hpos = 1;
    262         event.vpos = 2;
    263 
    264         claimed = panel_pos_event(panel, &event);
    265         PCUT_ASSERT_EQUALS(ui_claimed, claimed);
    266 
    267         PCUT_ASSERT_NOT_NULL(panel->cursor);
    268         PCUT_ASSERT_STR_EQUALS("b", panel->cursor->name);
    269         PCUT_ASSERT_INT_EQUALS(2, panel->cursor->size);
    270 
    271         /* Clicking below the last entry should select it */
    272         event.hpos = 1;
    273         event.vpos = 4;
    274         claimed = panel_pos_event(panel, &event);
    275         PCUT_ASSERT_EQUALS(ui_claimed, claimed);
    276 
    277         PCUT_ASSERT_NOT_NULL(panel->cursor);
    278         PCUT_ASSERT_STR_EQUALS("c", panel->cursor->name);
    279         PCUT_ASSERT_INT_EQUALS(3, panel->cursor->size);
    280 
    281         /* Clicking on the top edge should do a page-up */
    282         event.hpos = 1;
    283         event.vpos = 0;
    284         claimed = panel_pos_event(panel, &event);
    285         PCUT_ASSERT_EQUALS(ui_claimed, claimed);
    286 
    287         PCUT_ASSERT_NOT_NULL(panel->cursor);
    288         PCUT_ASSERT_STR_EQUALS("a", panel->cursor->name);
    289         PCUT_ASSERT_INT_EQUALS(1, panel->cursor->size);
    290 
    291         panel_destroy(panel);
    292         ui_window_destroy(window);
    293         ui_destroy(ui);
    294170}
    295171
     
    318194}
    319195
    320 /** panel_page_size() returns correct size */
    321 PCUT_TEST(page_size)
    322 {
    323         panel_t *panel;
    324         gfx_rect_t rect;
    325         errno_t rc;
    326 
    327         rc = panel_create(NULL, true, &panel);
    328         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    329 
    330         rect.p0.x = 10;
    331         rect.p0.y = 20;
    332         rect.p1.x = 30;
    333         rect.p1.y = 40;
    334 
    335         panel_set_rect(panel, &rect);
    336 
    337         /* NOTE If page size changes, we have problems elsewhere in the tests */
    338         PCUT_ASSERT_INT_EQUALS(18, panel_page_size(panel));
    339 
    340         panel_destroy(panel);
    341 }
    342 
    343196/** panel_is_active() returns panel activity state */
    344197PCUT_TEST(is_active)
     
    419272}
    420273
    421 /** panel_entry_append() appends new entry */
    422 PCUT_TEST(entry_append)
    423 {
    424         panel_t *panel;
    425         panel_entry_attr_t attr;
    426         errno_t rc;
    427 
    428         rc = panel_create(NULL, true, &panel);
    429         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    430 
    431         panel_entry_attr_init(&attr);
    432 
    433         attr.name = "a";
    434         attr.size = 1;
    435         rc = panel_entry_append(panel, &attr);
    436         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    437 
    438         PCUT_ASSERT_INT_EQUALS(1, list_count(&panel->entries));
    439 
    440         attr.name = "b";
    441         attr.size = 2;
    442         rc = panel_entry_append(panel, &attr);
    443         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    444 
    445         PCUT_ASSERT_INT_EQUALS(2, list_count(&panel->entries));
    446 
    447         panel_destroy(panel);
    448 }
    449 
    450 /** panel_entry_delete() deletes entry */
    451 PCUT_TEST(entry_delete)
    452 {
    453         panel_t *panel;
    454         panel_entry_t *entry;
    455         panel_entry_attr_t attr;
    456         errno_t rc;
    457 
    458         rc = panel_create(NULL, true, &panel);
    459         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    460 
    461         attr.name = "a";
    462         attr.size = 1;
    463         rc = panel_entry_append(panel, &attr);
    464         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    465 
    466         attr.name = "b";
    467         attr.size = 2;
    468         rc = panel_entry_append(panel, &attr);
    469         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    470 
    471         PCUT_ASSERT_INT_EQUALS(2, list_count(&panel->entries));
    472 
    473         entry = panel_first(panel);
    474         panel_entry_delete(entry);
    475 
    476         PCUT_ASSERT_INT_EQUALS(1, list_count(&panel->entries));
    477 
    478         entry = panel_first(panel);
    479         panel_entry_delete(entry);
    480 
    481         PCUT_ASSERT_INT_EQUALS(0, list_count(&panel->entries));
    482 
    483         panel_destroy(panel);
    484 }
    485 
    486 /** panel_clear_entries() removes all entries from panel */
    487 PCUT_TEST(clear_entries)
    488 {
    489         panel_t *panel;
    490         panel_entry_attr_t attr;
    491         errno_t rc;
    492 
    493         rc = panel_create(NULL, true, &panel);
    494         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    495 
    496         panel_entry_attr_init(&attr);
    497         attr.name = "a";
    498         attr.size = 1;
    499         rc = panel_entry_append(panel, &attr);
    500         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    501 
    502         attr.name = "a";
    503         attr.size = 2;
    504         rc = panel_entry_append(panel, &attr);
    505         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    506 
    507         PCUT_ASSERT_INT_EQUALS(2, list_count(&panel->entries));
    508 
    509         panel_clear_entries(panel);
    510         PCUT_ASSERT_INT_EQUALS(0, list_count(&panel->entries));
    511 
    512         panel_destroy(panel);
    513 }
    514 
    515 /** panel_read_dir() reads the contents of a directory */
    516 PCUT_TEST(read_dir)
    517 {
    518         panel_t *panel;
    519         panel_entry_t *entry;
    520         char buf[L_tmpnam];
    521         char *fname;
    522         char *p;
    523         errno_t rc;
    524         FILE *f;
    525         int rv;
    526 
    527         /* Create name for temporary directory */
    528         p = tmpnam(buf);
    529         PCUT_ASSERT_NOT_NULL(p);
    530 
    531         /* Create temporary directory */
    532         rc = vfs_link_path(p, KIND_DIRECTORY, NULL);
    533         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    534 
    535         rv = asprintf(&fname, "%s/%s", p, "a");
    536         PCUT_ASSERT_TRUE(rv >= 0);
    537 
    538         f = fopen(fname, "wb");
    539         PCUT_ASSERT_NOT_NULL(f);
    540 
    541         rv = fprintf(f, "X");
    542         PCUT_ASSERT_TRUE(rv >= 0);
    543 
    544         rv = fclose(f);
    545         PCUT_ASSERT_INT_EQUALS(0, rv);
    546 
    547         rc = panel_create(NULL, true, &panel);
    548         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    549 
    550         rc = panel_read_dir(panel, p);
    551         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    552 
    553         PCUT_ASSERT_INT_EQUALS(2, list_count(&panel->entries));
    554 
    555         entry = panel_first(panel);
    556         PCUT_ASSERT_NOT_NULL(entry);
    557         PCUT_ASSERT_STR_EQUALS("..", entry->name);
    558 
    559         entry = panel_next(entry);
    560         PCUT_ASSERT_NOT_NULL(entry);
    561         PCUT_ASSERT_STR_EQUALS("a", entry->name);
    562         PCUT_ASSERT_INT_EQUALS(1, entry->size);
    563 
    564         panel_destroy(panel);
    565 
    566         rv = remove(fname);
    567         PCUT_ASSERT_INT_EQUALS(0, rv);
    568 
    569         rv = remove(p);
    570         PCUT_ASSERT_INT_EQUALS(0, rv);
    571 
    572         free(fname);
    573 }
    574 
    575 /** When moving to parent directory from a subdir, we seek to the
    576  * coresponding entry
    577  */
    578 PCUT_TEST(read_dir_up)
    579 {
    580         panel_t *panel;
    581         char buf[L_tmpnam];
    582         char *subdir_a;
    583         char *subdir_b;
    584         char *subdir_c;
    585         char *p;
    586         errno_t rc;
    587         int rv;
    588 
    589         /* Create name for temporary directory */
    590         p = tmpnam(buf);
    591         PCUT_ASSERT_NOT_NULL(p);
    592 
    593         /* Create temporary directory */
    594         rc = vfs_link_path(p, KIND_DIRECTORY, NULL);
    595         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    596 
    597         /* Create some subdirectories */
    598 
    599         rv = asprintf(&subdir_a, "%s/%s", p, "a");
    600         PCUT_ASSERT_TRUE(rv >= 0);
    601         rc = vfs_link_path(subdir_a, KIND_DIRECTORY, NULL);
    602         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    603 
    604         rv = asprintf(&subdir_b, "%s/%s", p, "b");
    605         PCUT_ASSERT_TRUE(rv >= 0);
    606         rc = vfs_link_path(subdir_b, KIND_DIRECTORY, NULL);
    607         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    608 
    609         rv = asprintf(&subdir_c, "%s/%s", p, "c");
    610         PCUT_ASSERT_TRUE(rv >= 0);
    611         rc = vfs_link_path(subdir_c, KIND_DIRECTORY, NULL);
    612         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    613 
    614         rc = panel_create(NULL, true, &panel);
    615         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    616 
    617         /* Start in subdirectory "b" */
    618         rc = panel_read_dir(panel, subdir_b);
    619         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    620 
    621         /* Now go up (into p) */
    622 
    623         rc = panel_read_dir(panel, "..");
    624         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    625 
    626         PCUT_ASSERT_NOT_NULL(panel->cursor);
    627         PCUT_ASSERT_STR_EQUALS("b", panel->cursor->name);
    628 
    629         panel_destroy(panel);
    630 
    631         rv = remove(subdir_a);
    632         PCUT_ASSERT_INT_EQUALS(0, rv);
    633 
    634         rv = remove(subdir_b);
    635         PCUT_ASSERT_INT_EQUALS(0, rv);
    636 
    637         rv = remove(subdir_c);
    638         PCUT_ASSERT_INT_EQUALS(0, rv);
    639 
    640         rv = remove(p);
    641         PCUT_ASSERT_INT_EQUALS(0, rv);
    642 
    643         free(subdir_a);
    644         free(subdir_b);
    645         free(subdir_c);
    646 }
    647 
    648 /** panel_sort() sorts panel entries */
    649 PCUT_TEST(sort)
    650 {
    651         panel_t *panel;
    652         panel_entry_t *entry;
    653         panel_entry_attr_t attr;
    654         errno_t rc;
    655 
    656         rc = panel_create(NULL, true, &panel);
    657         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    658 
    659         panel_entry_attr_init(&attr);
    660 
    661         attr.name = "b";
    662         attr.size = 1;
    663         rc = panel_entry_append(panel, &attr);
    664         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    665 
    666         attr.name = "c";
    667         attr.size = 3;
    668         rc = panel_entry_append(panel, &attr);
    669         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    670 
    671         attr.name = "a";
    672         attr.size = 2;
    673         rc = panel_entry_append(panel, &attr);
    674         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    675 
    676         rc = panel_sort(panel);
    677         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    678 
    679         entry = panel_first(panel);
    680         PCUT_ASSERT_STR_EQUALS("a", entry->name);
    681         PCUT_ASSERT_INT_EQUALS(2, entry->size);
    682 
    683         entry = panel_next(entry);
    684         PCUT_ASSERT_STR_EQUALS("b", entry->name);
    685         PCUT_ASSERT_INT_EQUALS(1, entry->size);
    686 
    687         entry = panel_next(entry);
    688         PCUT_ASSERT_STR_EQUALS("c", entry->name);
    689         PCUT_ASSERT_INT_EQUALS(3, entry->size);
    690 
    691         panel_destroy(panel);
    692 }
    693 
    694 /** panel_entry_ptr_cmp compares two indirectly referenced entries */
    695 PCUT_TEST(entry_ptr_cmp)
    696 {
    697         panel_t *panel;
    698         panel_entry_t *a, *b;
    699         panel_entry_attr_t attr;
    700         int rel;
    701         errno_t rc;
    702 
    703         rc = panel_create(NULL, true, &panel);
    704         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    705 
    706         panel_entry_attr_init(&attr);
    707 
    708         attr.name = "a";
    709         attr.size = 2;
    710         rc = panel_entry_append(panel, &attr);
    711         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    712 
    713         attr.name = "b";
    714         attr.size = 1;
    715         rc = panel_entry_append(panel, &attr);
    716         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    717 
    718         a = panel_first(panel);
    719         PCUT_ASSERT_NOT_NULL(a);
    720         b = panel_next(a);
    721         PCUT_ASSERT_NOT_NULL(b);
    722 
    723         /* a < b */
    724         rel = panel_entry_ptr_cmp(&a, &b);
    725         PCUT_ASSERT_TRUE(rel < 0);
    726 
    727         /* b > a */
    728         rel = panel_entry_ptr_cmp(&b, &a);
    729         PCUT_ASSERT_TRUE(rel > 0);
    730 
    731         /* a == a */
    732         rel = panel_entry_ptr_cmp(&a, &a);
    733         PCUT_ASSERT_INT_EQUALS(0, rel);
    734 
    735         panel_destroy(panel);
    736 }
    737 
    738 /** panel_first() returns valid entry or @c NULL as appropriate */
    739 PCUT_TEST(first)
    740 {
    741         panel_t *panel;
    742         panel_entry_t *entry;
    743         panel_entry_attr_t attr;
    744         errno_t rc;
    745 
    746         rc = panel_create(NULL, true, &panel);
    747         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    748 
    749         panel_entry_attr_init(&attr);
    750 
    751         entry = panel_first(panel);
    752         PCUT_ASSERT_NULL(entry);
    753 
    754         /* Add one entry */
    755         attr.name = "a";
    756         attr.size = 1;
    757         rc = panel_entry_append(panel, &attr);
    758         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    759 
    760         /* Now try getting it */
    761         entry = panel_first(panel);
    762         PCUT_ASSERT_NOT_NULL(entry);
    763         PCUT_ASSERT_STR_EQUALS("a", entry->name);
    764         PCUT_ASSERT_INT_EQUALS(1, entry->size);
    765 
    766         /* Add another entry */
    767         attr.name = "b";
    768         attr.size = 2;
    769         rc = panel_entry_append(panel, &attr);
    770         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    771 
    772         /* We should still get the first entry */
    773         entry = panel_first(panel);
    774         PCUT_ASSERT_NOT_NULL(entry);
    775         PCUT_ASSERT_STR_EQUALS("a", entry->name);
    776         PCUT_ASSERT_INT_EQUALS(1, entry->size);
    777 
    778         panel_destroy(panel);
    779 }
    780 
    781 /** panel_last() returns valid entry or @c NULL as appropriate */
    782 PCUT_TEST(last)
    783 {
    784         panel_t *panel;
    785         panel_entry_t *entry;
    786         panel_entry_attr_t attr;
    787         errno_t rc;
    788 
    789         rc = panel_create(NULL, true, &panel);
    790         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    791 
    792         panel_entry_attr_init(&attr);
    793 
    794         entry = panel_last(panel);
    795         PCUT_ASSERT_NULL(entry);
    796 
    797         /* Add one entry */
    798         attr.name = "a";
    799         attr.size = 1;
    800         rc = panel_entry_append(panel, &attr);
    801         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    802 
    803         /* Now try getting it */
    804         entry = panel_last(panel);
    805         PCUT_ASSERT_NOT_NULL(entry);
    806         PCUT_ASSERT_STR_EQUALS("a", entry->name);
    807         PCUT_ASSERT_INT_EQUALS(1, entry->size);
    808 
    809         /* Add another entry */
    810         attr.name = "b";
    811         attr.size = 2;
    812         rc = panel_entry_append(panel, &attr);
    813         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    814 
    815         /* We should get new entry now */
    816         entry = panel_last(panel);
    817         PCUT_ASSERT_NOT_NULL(entry);
    818         attr.name = "b";
    819         attr.size = 2;
    820         PCUT_ASSERT_STR_EQUALS("b", entry->name);
    821         PCUT_ASSERT_INT_EQUALS(2, entry->size);
    822 
    823         panel_destroy(panel);
    824 }
    825 
    826 /** panel_next() returns the next entry or @c NULL as appropriate */
    827 PCUT_TEST(next)
    828 {
    829         panel_t *panel;
    830         panel_entry_t *entry;
    831         panel_entry_attr_t attr;
    832         errno_t rc;
    833 
    834         rc = panel_create(NULL, true, &panel);
    835         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    836 
    837         panel_entry_attr_init(&attr);
    838 
    839         /* Add one entry */
    840         attr.name = "a";
    841         attr.size = 1;
    842         rc = panel_entry_append(panel, &attr);
    843         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    844 
    845         /* Now try getting its successor */
    846         entry = panel_first(panel);
    847         PCUT_ASSERT_NOT_NULL(entry);
    848 
    849         entry = panel_next(entry);
    850         PCUT_ASSERT_NULL(entry);
    851 
    852         /* Add another entry */
    853         attr.name = "b";
    854         attr.size = 2;
    855         rc = panel_entry_append(panel, &attr);
    856         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    857 
    858         /* Try getting the successor of first entry again */
    859         entry = panel_first(panel);
    860         PCUT_ASSERT_NOT_NULL(entry);
    861 
    862         entry = panel_next(entry);
    863         PCUT_ASSERT_NOT_NULL(entry);
    864         PCUT_ASSERT_STR_EQUALS("b", entry->name);
    865         PCUT_ASSERT_INT_EQUALS(2, entry->size);
    866 
    867         panel_destroy(panel);
    868 }
    869 
    870 /** panel_prev() returns the previous entry or @c NULL as appropriate */
    871 PCUT_TEST(prev)
    872 {
    873         panel_t *panel;
    874         panel_entry_t *entry;
    875         panel_entry_attr_t attr;
    876         errno_t rc;
    877 
    878         rc = panel_create(NULL, true, &panel);
    879         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    880 
    881         panel_entry_attr_init(&attr);
    882 
    883         /* Add one entry */
    884         attr.name = "a";
    885         attr.size = 1;
    886         rc = panel_entry_append(panel, &attr);
    887         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    888 
    889         /* Now try getting its predecessor */
    890         entry = panel_last(panel);
    891         PCUT_ASSERT_NOT_NULL(entry);
    892 
    893         entry = panel_prev(entry);
    894         PCUT_ASSERT_NULL(entry);
    895 
    896         /* Add another entry */
    897         attr.name = "b";
    898         attr.size = 2;
    899         rc = panel_entry_append(panel, &attr);
    900         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    901 
    902         /* Try getting the predecessor of the new entry */
    903         entry = panel_last(panel);
    904         PCUT_ASSERT_NOT_NULL(entry);
    905 
    906         entry = panel_prev(entry);
    907         PCUT_ASSERT_NOT_NULL(entry);
    908         PCUT_ASSERT_STR_EQUALS("a", entry->name);
    909         PCUT_ASSERT_INT_EQUALS(1, entry->size);
    910 
    911         panel_destroy(panel);
    912 }
    913 
    914 /** panel_page_nth_entry() .. */
    915 PCUT_TEST(page_nth_entry)
    916 {
    917         panel_t *panel;
    918         panel_entry_t *entry;
    919         panel_entry_attr_t attr;
    920         size_t idx;
    921         errno_t rc;
    922 
    923         rc = panel_create(NULL, true, &panel);
    924         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    925 
    926         panel_entry_attr_init(&attr);
    927 
    928         /* Add some entries */
    929         attr.name = "a";
    930         attr.size = 1;
    931         rc = panel_entry_append(panel, &attr);
    932         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    933 
    934         attr.name = "b";
    935         attr.size = 2;
    936         rc = panel_entry_append(panel, &attr);
    937         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    938 
    939         attr.name = "c";
    940         attr.size = 3;
    941         rc = panel_entry_append(panel, &attr);
    942         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    943 
    944         panel->page = panel_next(panel_first(panel));
    945         panel->page_idx = 1;
    946 
    947         entry = panel_page_nth_entry(panel, 0, &idx);
    948         PCUT_ASSERT_STR_EQUALS("b", entry->name);
    949         PCUT_ASSERT_INT_EQUALS(1, idx);
    950 
    951         entry = panel_page_nth_entry(panel, 1, &idx);
    952         PCUT_ASSERT_STR_EQUALS("c", entry->name);
    953         PCUT_ASSERT_INT_EQUALS(2, idx);
    954 
    955         entry = panel_page_nth_entry(panel, 2, &idx);
    956         PCUT_ASSERT_STR_EQUALS("c", entry->name);
    957         PCUT_ASSERT_INT_EQUALS(2, idx);
    958 
    959         entry = panel_page_nth_entry(panel, 3, &idx);
    960         PCUT_ASSERT_STR_EQUALS("c", entry->name);
    961         PCUT_ASSERT_INT_EQUALS(2, idx);
    962 
    963         panel_destroy(panel);
    964 }
    965 
    966 /** panel_cursor_move() ... */
    967 PCUT_TEST(cursor_move)
    968 {
    969 }
    970 
    971 /** panel_cursor_up() moves cursor one entry up */
    972 PCUT_TEST(cursor_up)
    973 {
    974         ui_t *ui;
    975         ui_window_t *window;
    976         ui_wnd_params_t params;
    977         panel_t *panel;
    978         panel_entry_attr_t attr;
    979         gfx_rect_t rect;
    980         errno_t rc;
    981 
    982         rc = ui_create_disp(NULL, &ui);
    983         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    984 
    985         ui_wnd_params_init(&params);
    986         params.caption = "Test";
    987 
    988         rc = ui_window_create(ui, &params, &window);
    989         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    990 
    991         rc = panel_create(window, true, &panel);
    992         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    993 
    994         rect.p0.x = 0;
    995         rect.p0.y = 0;
    996         rect.p1.x = 10;
    997         rect.p1.y = 4; // XXX Assuming this makes page size 2
    998         panel_set_rect(panel, &rect);
    999 
    1000         PCUT_ASSERT_INT_EQUALS(2, panel_page_size(panel));
    1001 
    1002         /* Add tree entries (more than page size, which is 2) */
    1003 
    1004         panel_entry_attr_init(&attr);
    1005 
    1006         attr.name = "a";
    1007         attr.size = 1;
    1008         rc = panel_entry_append(panel, &attr);
    1009         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1010 
    1011         attr.name = "b";
    1012         attr.size = 2;
    1013         rc = panel_entry_append(panel, &attr);
    1014         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1015 
    1016         attr.name = "c";
    1017         attr.size = 3;
    1018         rc = panel_entry_append(panel, &attr);
    1019         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1020 
    1021         /* Cursor to the last entry and page start to the next-to-last entry */
    1022         panel->cursor = panel_last(panel);
    1023         panel->cursor_idx = 2;
    1024         panel->page = panel_prev(panel->cursor);
    1025         panel->page_idx = 1;
    1026 
    1027         /* Move cursor one entry up */
    1028         panel_cursor_up(panel);
    1029 
    1030         /* Cursor and page start should now both be at the second entry */
    1031         PCUT_ASSERT_STR_EQUALS("b", panel->cursor->name);
    1032         PCUT_ASSERT_INT_EQUALS(2, panel->cursor->size);
    1033         PCUT_ASSERT_INT_EQUALS(1, panel->cursor_idx);
    1034         PCUT_ASSERT_EQUALS(panel->cursor, panel->page);
    1035         PCUT_ASSERT_INT_EQUALS(1, panel->page_idx);
    1036 
    1037         /* Move cursor one entry up. This should scroll up. */
    1038         panel_cursor_up(panel);
    1039 
    1040         /* Cursor and page start should now both be at the first entry */
    1041         PCUT_ASSERT_STR_EQUALS("a", panel->cursor->name);
    1042         PCUT_ASSERT_INT_EQUALS(1, panel->cursor->size);
    1043         PCUT_ASSERT_INT_EQUALS(0, panel->cursor_idx);
    1044         PCUT_ASSERT_EQUALS(panel->cursor, panel->page);
    1045         PCUT_ASSERT_INT_EQUALS(0, panel->page_idx);
    1046 
    1047         /* Moving further up should do nothing (we are at the top). */
    1048         panel_cursor_up(panel);
    1049 
    1050         /* Cursor and page start should still be at the first entry */
    1051         PCUT_ASSERT_STR_EQUALS("a", panel->cursor->name);
    1052         PCUT_ASSERT_INT_EQUALS(1, panel->cursor->size);
    1053         PCUT_ASSERT_INT_EQUALS(0, panel->cursor_idx);
    1054         PCUT_ASSERT_EQUALS(panel->cursor, panel->page);
    1055         PCUT_ASSERT_INT_EQUALS(0, panel->page_idx);
    1056 
    1057         panel_destroy(panel);
    1058         ui_window_destroy(window);
    1059         ui_destroy(ui);
    1060 }
    1061 
    1062 /** panel_cursor_down() moves cursor one entry down */
    1063 PCUT_TEST(cursor_down)
    1064 {
    1065         ui_t *ui;
    1066         ui_window_t *window;
    1067         ui_wnd_params_t params;
    1068         panel_t *panel;
    1069         panel_entry_attr_t attr;
    1070         gfx_rect_t rect;
    1071         errno_t rc;
    1072 
    1073         rc = ui_create_disp(NULL, &ui);
    1074         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1075 
    1076         ui_wnd_params_init(&params);
    1077         params.caption = "Test";
    1078 
    1079         rc = ui_window_create(ui, &params, &window);
    1080         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1081 
    1082         rc = panel_create(window, true, &panel);
    1083         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1084 
    1085         rect.p0.x = 0;
    1086         rect.p0.y = 0;
    1087         rect.p1.x = 10;
    1088         rect.p1.y = 4; // XXX Assuming this makes page size 2
    1089         panel_set_rect(panel, &rect);
    1090 
    1091         PCUT_ASSERT_INT_EQUALS(2, panel_page_size(panel));
    1092 
    1093         /* Add tree entries (more than page size, which is 2) */
    1094 
    1095         panel_entry_attr_init(&attr);
    1096 
    1097         attr.name = "a";
    1098         attr.size = 1;
    1099         rc = panel_entry_append(panel, &attr);
    1100         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1101 
    1102         attr.name = "b";
    1103         attr.size = 2;
    1104         rc = panel_entry_append(panel, &attr);
    1105         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1106 
    1107         attr.name = "c";
    1108         attr.size = 3;
    1109         rc = panel_entry_append(panel, &attr);
    1110         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1111 
    1112         /* Cursor and page start to the first entry */
    1113         panel->cursor = panel_first(panel);
    1114         panel->cursor_idx = 0;
    1115         panel->page = panel->cursor;
    1116         panel->page_idx = 0;
    1117 
    1118         /* Move cursor one entry down */
    1119         panel_cursor_down(panel);
    1120 
    1121         /* Cursor should now be at the second entry, page stays the same */
    1122         PCUT_ASSERT_STR_EQUALS("b", panel->cursor->name);
    1123         PCUT_ASSERT_INT_EQUALS(2, panel->cursor->size);
    1124         PCUT_ASSERT_INT_EQUALS(1, panel->cursor_idx);
    1125         PCUT_ASSERT_EQUALS(panel_first(panel), panel->page);
    1126         PCUT_ASSERT_INT_EQUALS(0, panel->page_idx);
    1127 
    1128         /* Move cursor one entry down. This should scroll down. */
    1129         panel_cursor_down(panel);
    1130 
    1131         /* Cursor should now be at the third and page at the second entry. */
    1132         PCUT_ASSERT_STR_EQUALS("c", panel->cursor->name);
    1133         PCUT_ASSERT_INT_EQUALS(3, panel->cursor->size);
    1134         PCUT_ASSERT_INT_EQUALS(2, panel->cursor_idx);
    1135         PCUT_ASSERT_STR_EQUALS("b", panel->page->name);
    1136         PCUT_ASSERT_INT_EQUALS(2, panel->page->size);
    1137         PCUT_ASSERT_INT_EQUALS(1, panel->page_idx);
    1138 
    1139         /* Moving further down should do nothing (we are at the bottom). */
    1140         panel_cursor_down(panel);
    1141 
    1142         /* Cursor should still be at the third and page at the second entry. */
    1143         PCUT_ASSERT_STR_EQUALS("c", panel->cursor->name);
    1144         PCUT_ASSERT_INT_EQUALS(3, panel->cursor->size);
    1145         PCUT_ASSERT_INT_EQUALS(2, panel->cursor_idx);
    1146         PCUT_ASSERT_STR_EQUALS("b", panel->page->name);
    1147         PCUT_ASSERT_INT_EQUALS(2, panel->page->size);
    1148         PCUT_ASSERT_INT_EQUALS(1, panel->page_idx);
    1149 
    1150         panel_destroy(panel);
    1151         ui_window_destroy(window);
    1152         ui_destroy(ui);
    1153 }
    1154 
    1155 /** panel_cursor_top() moves cursor to the first entry */
    1156 PCUT_TEST(cursor_top)
    1157 {
    1158         ui_t *ui;
    1159         ui_window_t *window;
    1160         ui_wnd_params_t params;
    1161         panel_t *panel;
    1162         panel_entry_attr_t attr;
    1163         gfx_rect_t rect;
    1164         errno_t rc;
    1165 
    1166         rc = ui_create_disp(NULL, &ui);
    1167         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1168 
    1169         ui_wnd_params_init(&params);
    1170         params.caption = "Test";
    1171 
    1172         rc = ui_window_create(ui, &params, &window);
    1173         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1174 
    1175         rc = panel_create(window, true, &panel);
    1176         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1177 
    1178         rect.p0.x = 0;
    1179         rect.p0.y = 0;
    1180         rect.p1.x = 10;
    1181         rect.p1.y = 4; // XXX Assuming this makes page size 2
    1182         panel_set_rect(panel, &rect);
    1183 
    1184         PCUT_ASSERT_INT_EQUALS(2, panel_page_size(panel));
    1185 
    1186         /* Add tree entries (more than page size, which is 2) */
    1187 
    1188         panel_entry_attr_init(&attr);
    1189 
    1190         attr.name = "a";
    1191         attr.size = 1;
    1192         rc = panel_entry_append(panel, &attr);
    1193         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1194 
    1195         attr.name = "b";
    1196         attr.size = 2;
    1197         rc = panel_entry_append(panel, &attr);
    1198         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1199 
    1200         attr.name = "c";
    1201         attr.size = 3;
    1202         rc = panel_entry_append(panel, &attr);
    1203         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1204 
    1205         /* Cursor to the last entry and page start to the next-to-last entry */
    1206         panel->cursor = panel_last(panel);
    1207         panel->cursor_idx = 2;
    1208         panel->page = panel_prev(panel->cursor);
    1209         panel->page_idx = 1;
    1210 
    1211         /* Move cursor to the top. This should scroll up. */
    1212         panel_cursor_top(panel);
    1213 
    1214         /* Cursor and page start should now both be at the first entry */
    1215         PCUT_ASSERT_STR_EQUALS("a", panel->cursor->name);
    1216         PCUT_ASSERT_INT_EQUALS(1, panel->cursor->size);
    1217         PCUT_ASSERT_INT_EQUALS(0, panel->cursor_idx);
    1218         PCUT_ASSERT_EQUALS(panel->cursor, panel->page);
    1219         PCUT_ASSERT_INT_EQUALS(0, panel->page_idx);
    1220 
    1221         panel_destroy(panel);
    1222         ui_window_destroy(window);
    1223         ui_destroy(ui);
    1224 }
    1225 
    1226 /** panel_cursor_bottom() moves cursor to the last entry */
    1227 PCUT_TEST(cursor_bottom)
    1228 {
    1229         ui_t *ui;
    1230         ui_window_t *window;
    1231         ui_wnd_params_t params;
    1232         panel_t *panel;
    1233         panel_entry_attr_t attr;
    1234         gfx_rect_t rect;
    1235         errno_t rc;
    1236 
    1237         rc = ui_create_disp(NULL, &ui);
    1238         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1239 
    1240         ui_wnd_params_init(&params);
    1241         params.caption = "Test";
    1242 
    1243         rc = ui_window_create(ui, &params, &window);
    1244         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1245 
    1246         rc = panel_create(window, true, &panel);
    1247         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1248 
    1249         rect.p0.x = 0;
    1250         rect.p0.y = 0;
    1251         rect.p1.x = 10;
    1252         rect.p1.y = 4; // XXX Assuming this makes page size 2
    1253         panel_set_rect(panel, &rect);
    1254 
    1255         PCUT_ASSERT_INT_EQUALS(2, panel_page_size(panel));
    1256 
    1257         /* Add tree entries (more than page size, which is 2) */
    1258 
    1259         panel_entry_attr_init(&attr);
    1260 
    1261         attr.name = "a";
    1262         attr.size = 1;
    1263         rc = panel_entry_append(panel, &attr);
    1264         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1265 
    1266         attr.name = "b";
    1267         attr.size = 2;
    1268         rc = panel_entry_append(panel, &attr);
    1269         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1270 
    1271         attr.name = "c";
    1272         attr.size = 3;
    1273         rc = panel_entry_append(panel, &attr);
    1274         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1275 
    1276         /* Cursor and page start to the first entry */
    1277         panel->cursor = panel_first(panel);
    1278         panel->cursor_idx = 0;
    1279         panel->page = panel->cursor;
    1280         panel->page_idx = 0;
    1281 
    1282         /* Move cursor to the bottom. This should scroll down. */
    1283         panel_cursor_bottom(panel);
    1284 
    1285         /* Cursor should now be at the third and page at the second entry. */
    1286         PCUT_ASSERT_STR_EQUALS("c", panel->cursor->name);
    1287         PCUT_ASSERT_INT_EQUALS(3, panel->cursor->size);
    1288         PCUT_ASSERT_INT_EQUALS(2, panel->cursor_idx);
    1289         PCUT_ASSERT_STR_EQUALS("b", panel->page->name);
    1290         PCUT_ASSERT_INT_EQUALS(2, panel->page->size);
    1291         PCUT_ASSERT_INT_EQUALS(1, panel->page_idx);
    1292 
    1293         panel_destroy(panel);
    1294         ui_window_destroy(window);
    1295         ui_destroy(ui);
    1296 }
    1297 
    1298 /** panel_page_up() moves one page up */
    1299 PCUT_TEST(page_up)
    1300 {
    1301         ui_t *ui;
    1302         ui_window_t *window;
    1303         ui_wnd_params_t params;
    1304         panel_t *panel;
    1305         panel_entry_attr_t attr;
    1306         gfx_rect_t rect;
    1307         errno_t rc;
    1308 
    1309         rc = ui_create_disp(NULL, &ui);
    1310         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1311 
    1312         ui_wnd_params_init(&params);
    1313         params.caption = "Test";
    1314 
    1315         rc = ui_window_create(ui, &params, &window);
    1316         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1317 
    1318         rc = panel_create(window, true, &panel);
    1319         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1320 
    1321         rect.p0.x = 0;
    1322         rect.p0.y = 0;
    1323         rect.p1.x = 10;
    1324         rect.p1.y = 4; // XXX Assuming this makes page size 2
    1325         panel_set_rect(panel, &rect);
    1326 
    1327         PCUT_ASSERT_INT_EQUALS(2, panel_page_size(panel));
    1328 
    1329         /* Add five entries (2 full pages, one partial) */
    1330 
    1331         panel_entry_attr_init(&attr);
    1332 
    1333         attr.name = "a";
    1334         attr.size = 1;
    1335         rc = panel_entry_append(panel, &attr);
    1336         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1337 
    1338         attr.name = "b";
    1339         attr.size = 2;
    1340         rc = panel_entry_append(panel, &attr);
    1341         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1342 
    1343         attr.name = "c";
    1344         attr.size = 3;
    1345         rc = panel_entry_append(panel, &attr);
    1346         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1347 
    1348         attr.name = "d";
    1349         attr.size = 4;
    1350         rc = panel_entry_append(panel, &attr);
    1351         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1352 
    1353         attr.name = "e";
    1354         attr.size = 5;
    1355         rc = panel_entry_append(panel, &attr);
    1356         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1357 
    1358         /* Cursor to the last entry and page start to the next-to-last entry */
    1359         panel->cursor = panel_last(panel);
    1360         panel->cursor_idx = 4;
    1361         panel->page = panel_prev(panel->cursor);
    1362         panel->page_idx = 3;
    1363 
    1364         /* Move one page up */
    1365         panel_page_up(panel);
    1366 
    1367         /* Page should now start at second entry and cursor at third */
    1368         PCUT_ASSERT_STR_EQUALS("c", panel->cursor->name);
    1369         PCUT_ASSERT_INT_EQUALS(3, panel->cursor->size);
    1370         PCUT_ASSERT_INT_EQUALS(2, panel->cursor_idx);
    1371         PCUT_ASSERT_STR_EQUALS("b", panel->page->name);
    1372         PCUT_ASSERT_INT_EQUALS(2, panel->page->size);
    1373         PCUT_ASSERT_INT_EQUALS(1, panel->page_idx);
    1374 
    1375         /* Move one page up again. */
    1376         panel_page_up(panel);
    1377 
    1378         /* Cursor and page start should now both be at the first entry */
    1379         PCUT_ASSERT_STR_EQUALS("a", panel->cursor->name);
    1380         PCUT_ASSERT_INT_EQUALS(1, panel->cursor->size);
    1381         PCUT_ASSERT_INT_EQUALS(0, panel->cursor_idx);
    1382         PCUT_ASSERT_EQUALS(panel->cursor, panel->page);
    1383         PCUT_ASSERT_INT_EQUALS(0, panel->page_idx);
    1384 
    1385         /* Moving further up should do nothing (we are at the top). */
    1386         panel_page_up(panel);
    1387 
    1388         /* Cursor and page start should still be at the first entry */
    1389         PCUT_ASSERT_STR_EQUALS("a", panel->cursor->name);
    1390         PCUT_ASSERT_INT_EQUALS(1, panel->cursor->size);
    1391         PCUT_ASSERT_INT_EQUALS(0, panel->cursor_idx);
    1392         PCUT_ASSERT_EQUALS(panel->cursor, panel->page);
    1393         PCUT_ASSERT_INT_EQUALS(0, panel->page_idx);
    1394 
    1395         panel_destroy(panel);
    1396         ui_window_destroy(window);
    1397         ui_destroy(ui);
    1398 }
    1399 
    1400 /** panel_page_up() moves one page down */
    1401 PCUT_TEST(page_down)
    1402 {
    1403         ui_t *ui;
    1404         ui_window_t *window;
    1405         ui_wnd_params_t params;
    1406         panel_t *panel;
    1407         panel_entry_attr_t attr;
    1408         gfx_rect_t rect;
    1409         errno_t rc;
    1410 
    1411         rc = ui_create_disp(NULL, &ui);
    1412         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1413 
    1414         ui_wnd_params_init(&params);
    1415         params.caption = "Test";
    1416 
    1417         rc = ui_window_create(ui, &params, &window);
    1418         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1419 
    1420         rc = panel_create(window, true, &panel);
    1421         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1422 
    1423         rect.p0.x = 0;
    1424         rect.p0.y = 0;
    1425         rect.p1.x = 10;
    1426         rect.p1.y = 4; // XXX Assuming this makes page size 2
    1427         panel_set_rect(panel, &rect);
    1428 
    1429         PCUT_ASSERT_INT_EQUALS(2, panel_page_size(panel));
    1430 
    1431         /* Add five entries (2 full pages, one partial) */
    1432 
    1433         panel_entry_attr_init(&attr);
    1434 
    1435         attr.name = "a";
    1436         attr.size = 1;
    1437         rc = panel_entry_append(panel, &attr);
    1438         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1439 
    1440         attr.name = "b";
    1441         attr.size = 2;
    1442         rc = panel_entry_append(panel, &attr);
    1443         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1444 
    1445         attr.name = "c";
    1446         attr.size = 3;
    1447         rc = panel_entry_append(panel, &attr);
    1448         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1449 
    1450         attr.name = "d";
    1451         attr.size = 4;
    1452         rc = panel_entry_append(panel, &attr);
    1453         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1454 
    1455         attr.name = "e";
    1456         attr.size = 5;
    1457         rc = panel_entry_append(panel, &attr);
    1458         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1459 
    1460         /* Cursor and page to the first entry */
    1461         panel->cursor = panel_first(panel);
    1462         panel->cursor_idx = 0;
    1463         panel->page = panel->cursor;
    1464         panel->page_idx = 0;
    1465 
    1466         /* Move one page down */
    1467         panel_page_down(panel);
    1468 
    1469         /* Page and cursor should point to the third entry */
    1470         PCUT_ASSERT_STR_EQUALS("c", panel->cursor->name);
    1471         PCUT_ASSERT_INT_EQUALS(3, panel->cursor->size);
    1472         PCUT_ASSERT_INT_EQUALS(2, panel->cursor_idx);
    1473         PCUT_ASSERT_STR_EQUALS("c", panel->page->name);
    1474         PCUT_ASSERT_INT_EQUALS(3, panel->page->size);
    1475         PCUT_ASSERT_INT_EQUALS(2, panel->page_idx);
    1476 
    1477         /* Move one page down again. */
    1478         panel_page_down(panel);
    1479 
    1480         /* Cursor should point to last and page to next-to-last entry */
    1481         PCUT_ASSERT_STR_EQUALS("e", panel->cursor->name);
    1482         PCUT_ASSERT_INT_EQUALS(5, panel->cursor->size);
    1483         PCUT_ASSERT_INT_EQUALS(4, panel->cursor_idx);
    1484         PCUT_ASSERT_STR_EQUALS("d", panel->page->name);
    1485         PCUT_ASSERT_INT_EQUALS(4, panel->page->size);
    1486         PCUT_ASSERT_INT_EQUALS(3, panel->page_idx);
    1487 
    1488         /* Moving further down should do nothing (we are at the bottom). */
    1489         panel_page_down(panel);
    1490 
    1491         /* Cursor should still point to last and page to next-to-last entry */
    1492         PCUT_ASSERT_STR_EQUALS("e", panel->cursor->name);
    1493         PCUT_ASSERT_INT_EQUALS(5, panel->cursor->size);
    1494         PCUT_ASSERT_INT_EQUALS(4, panel->cursor_idx);
    1495         PCUT_ASSERT_STR_EQUALS("d", panel->page->name);
    1496         PCUT_ASSERT_INT_EQUALS(4, panel->page->size);
    1497         PCUT_ASSERT_INT_EQUALS(3, panel->page_idx);
    1498 
    1499         panel_destroy(panel);
    1500         ui_window_destroy(window);
    1501         ui_destroy(ui);
    1502 }
    1503 
    1504 /** panel_open() opens a directory entry */
    1505 PCUT_TEST(open)
    1506 {
    1507         ui_t *ui;
    1508         ui_window_t *window;
    1509         ui_wnd_params_t params;
    1510         panel_t *panel;
    1511         panel_entry_t *entry;
    1512         char buf[L_tmpnam];
    1513         char *sdname;
    1514         char *p;
    1515         errno_t rc;
    1516         int rv;
    1517 
    1518         rc = ui_create_disp(NULL, &ui);
    1519         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1520 
    1521         ui_wnd_params_init(&params);
    1522         params.caption = "Test";
    1523 
    1524         rc = ui_window_create(ui, &params, &window);
    1525         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1526 
    1527         /* Create name for temporary directory */
    1528         p = tmpnam(buf);
    1529         PCUT_ASSERT_NOT_NULL(p);
    1530 
    1531         /* Create temporary directory */
    1532         rc = vfs_link_path(p, KIND_DIRECTORY, NULL);
    1533         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1534 
    1535         rv = asprintf(&sdname, "%s/%s", p, "a");
    1536         PCUT_ASSERT_TRUE(rv >= 0);
    1537 
    1538         /* Create sub-directory */
    1539         rc = vfs_link_path(sdname, KIND_DIRECTORY, NULL);
    1540         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1541 
    1542         rc = panel_create(window, true, &panel);
    1543         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1544 
    1545         rc = panel_read_dir(panel, p);
    1546         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1547         PCUT_ASSERT_STR_EQUALS(p, panel->dir);
    1548 
    1549         PCUT_ASSERT_INT_EQUALS(2, list_count(&panel->entries));
    1550 
    1551         entry = panel_first(panel);
    1552         PCUT_ASSERT_NOT_NULL(entry);
    1553         PCUT_ASSERT_STR_EQUALS("..", entry->name);
    1554 
    1555         entry = panel_next(entry);
    1556         PCUT_ASSERT_NOT_NULL(entry);
    1557         PCUT_ASSERT_STR_EQUALS("a", entry->name);
    1558         PCUT_ASSERT_TRUE(entry->isdir);
    1559 
    1560         rc = panel_open(panel, entry);
    1561         PCUT_ASSERT_ERRNO_VAL(EOK, rc);
    1562 
    1563         PCUT_ASSERT_STR_EQUALS(sdname, panel->dir);
    1564 
    1565         panel_destroy(panel);
    1566         ui_window_destroy(window);
    1567         ui_destroy(ui);
    1568 
    1569         rv = remove(sdname);
    1570         PCUT_ASSERT_INT_EQUALS(0, rv);
    1571 
    1572         rv = remove(p);
    1573         PCUT_ASSERT_INT_EQUALS(0, rv);
    1574 
    1575         free(sdname);
    1576 }
    1577 
    1578274/** panel_activate_req() sends activation request */
    1579275PCUT_TEST(activate_req)
  • uspace/app/nav/types/panel.h

    r453f9645 r54ddb59  
    11/*
    2  * Copyright (c) 2021 Jiri Svoboda
     2 * Copyright (c) 2022 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    3737#define TYPES_PANEL_H
    3838
    39 #include <adt/list.h>
    4039#include <gfx/color.h>
    4140#include <gfx/coord.h>
    42 #include <ipc/loc.h>
     41#include <ui/filelist.h>
    4342#include <ui/window.h>
    4443#include <stdint.h>
    45 
    46 /** Panel entry attributes */
    47 typedef struct {
    48         /** File name */
    49         const char *name;
    50         /** File size */
    51         uint64_t size;
    52         /** @c true iff entry is a directory */
    53         bool isdir;
    54         /** Service number for service special entries */
    55         service_id_t svc;
    56 } panel_entry_attr_t;
    57 
    58 /** Panel entry */
    59 typedef struct {
    60         /** Containing panel */
    61         struct panel *panel;
    62         /** Link to @c panel->entries */
    63         link_t lentries;
    64         /** File name */
    65         char *name;
    66         /** File size */
    67         uint64_t size;
    68         /** @c true iff entry is a directory */
    69         bool isdir;
    70         /** Service number for service special entries */
    71         service_id_t svc;
    72 } panel_entry_t;
    7344
    7445/** Navigator panel
     
    9566        gfx_color_t *color;
    9667
    97         /** Panel cursor color */
    98         gfx_color_t *curs_color;
    99 
    10068        /** Active border color */
    10169        gfx_color_t *act_border_color;
    102 
    103         /** Directory-type entry color */
    104         gfx_color_t *dir_color;
    105 
    106         /** Service-type entry color */
    107         gfx_color_t *svc_color;
    108 
    109         /** Panel entries (list of panel_entry_t) */
    110         list_t entries;
    111 
    112         /** Number of entries */
    113         size_t entries_cnt;
    114 
    115         /** First entry of current page */
    116         panel_entry_t *page;
    117 
    118         /** Index of first entry of current page */
    119         size_t page_idx;
    120 
    121         /** Cursor position */
    122         panel_entry_t *cursor;
    123 
    124         /** Index of entry under cursor */
    125         size_t cursor_idx;
    12670
    12771        /** @c true iff the panel is active */
    12872        bool active;
    12973
    130         /** Directory */
    131         char *dir;
     74        /** File list */
     75        ui_file_list_t *flist;
    13276} panel_t;
    13377
  • uspace/lib/ui/include/ui/filelist.h

    r453f9645 r54ddb59  
    5454extern errno_t ui_file_list_activate(ui_file_list_t *);
    5555extern void ui_file_list_deactivate(ui_file_list_t *);
     56extern errno_t ui_file_list_open(ui_file_list_t *, ui_file_list_entry_t *);
     57extern ui_file_list_entry_t *ui_file_list_get_cursor(ui_file_list_t *);
    5658
    5759#endif
  • uspace/lib/ui/private/filelist.h

    r453f9645 r54ddb59  
    164164extern void ui_file_list_scroll_page_down(ui_file_list_t *);
    165165extern void ui_file_list_scroll_pos(ui_file_list_t *, size_t);
    166 extern errno_t ui_file_list_open(ui_file_list_t *, ui_file_list_entry_t *);
    167166extern errno_t ui_file_list_open_dir(ui_file_list_t *, ui_file_list_entry_t *);
    168167extern errno_t ui_file_list_open_file(ui_file_list_t *, ui_file_list_entry_t *);
  • uspace/lib/ui/src/filelist.c

    r453f9645 r54ddb59  
    10791079}
    10801080
     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
    10811091/** Move cursor to a new position, possibly scrolling.
    10821092 *
Note: See TracChangeset for help on using the changeset viewer.