source: mainline/uspace/app/nav/panel.c@ 75357c5

Last change on this file since 75357c5 was 75357c5, checked in by Jiri Svoboda <jiri@…>, 4 years ago

Different color for service-special files

  • Property mode set to 100644
File size: 20.4 KB
RevLine 
[68b9e540]1/*
2 * Copyright (c) 2021 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup nav
30 * @{
31 */
32/** @file Navigator panel.
33 *
34 * Displays a file listing.
35 */
36
[8e5f39d]37#include <dirent.h>
[68b9e540]38#include <errno.h>
[0e5ed803]39#include <gfx/render.h>
[8e5f39d]40#include <gfx/text.h>
[68b9e540]41#include <stdlib.h>
[3b67e95]42#include <str.h>
[0e5ed803]43#include <ui/control.h>
44#include <ui/paint.h>
[8e5f39d]45#include <ui/resource.h>
[9bed565]46#include <vfs/vfs.h>
[03c4b23]47#include <qsort.h>
[68b9e540]48#include "panel.h"
49#include "nav.h"
50
[0e5ed803]51static void panel_ctl_destroy(void *);
52static errno_t panel_ctl_paint(void *);
[af2ea83]53static ui_evclaim_t panel_ctl_kbd_event(void *, kbd_event_t *);
[0e5ed803]54static ui_evclaim_t panel_ctl_pos_event(void *, pos_event_t *);
55
56/** Panel control ops */
57ui_control_ops_t panel_ctl_ops = {
58 .destroy = panel_ctl_destroy,
59 .paint = panel_ctl_paint,
[af2ea83]60 .kbd_event = panel_ctl_kbd_event,
[0e5ed803]61 .pos_event = panel_ctl_pos_event
62};
63
[68b9e540]64/** Create panel.
65 *
[0e5ed803]66 * @param window Containing window
[fe5c7a1]67 * @param active @c true iff panel should be active
[68b9e540]68 * @param rpanel Place to store pointer to new panel
69 * @return EOK on success or an error code
70 */
[fe5c7a1]71errno_t panel_create(ui_window_t *window, bool active, panel_t **rpanel)
[68b9e540]72{
73 panel_t *panel;
[0e5ed803]74 errno_t rc;
[68b9e540]75
76 panel = calloc(1, sizeof(panel_t));
77 if (panel == NULL)
78 return ENOMEM;
79
[0e5ed803]80 rc = ui_control_new(&panel_ctl_ops, (void *)panel,
81 &panel->control);
82 if (rc != EOK) {
83 free(panel);
84 return rc;
85 }
86
87 rc = gfx_color_new_ega(0x07, &panel->color);
88 if (rc != EOK)
89 goto error;
90
[8e5f39d]91 rc = gfx_color_new_ega(0x30, &panel->curs_color);
92 if (rc != EOK)
93 goto error;
94
[fe5c7a1]95 rc = gfx_color_new_ega(0x0f, &panel->act_border_color);
96 if (rc != EOK)
97 goto error;
98
[9bed565]99 rc = gfx_color_new_ega(0x0f, &panel->dir_color);
100 if (rc != EOK)
101 goto error;
102
[75357c5]103 rc = gfx_color_new_ega(0x0a, &panel->svc_color);
104 if (rc != EOK)
105 goto error;
106
[0e5ed803]107 panel->window = window;
[3b67e95]108 list_initialize(&panel->entries);
[af2ea83]109 panel->entries_cnt = 0;
[fe5c7a1]110 panel->active = active;
[68b9e540]111 *rpanel = panel;
112 return EOK;
[0e5ed803]113error:
[8e5f39d]114 if (panel->color != NULL)
115 gfx_color_delete(panel->color);
116 if (panel->curs_color != NULL)
117 gfx_color_delete(panel->curs_color);
[9bed565]118 if (panel->act_border_color != NULL)
119 gfx_color_delete(panel->act_border_color);
120 if (panel->dir_color != NULL)
121 gfx_color_delete(panel->dir_color);
[75357c5]122 if (panel->svc_color != NULL)
123 gfx_color_delete(panel->svc_color);
[0e5ed803]124 ui_control_delete(panel->control);
125 free(panel);
126 return rc;
[68b9e540]127}
128
129/** Destroy panel.
130 *
131 * @param panel Panel
132 */
133void panel_destroy(panel_t *panel)
134{
[8e5f39d]135 gfx_color_delete(panel->color);
136 gfx_color_delete(panel->curs_color);
[fe5c7a1]137 gfx_color_delete(panel->act_border_color);
[9bed565]138 gfx_color_delete(panel->dir_color);
[75357c5]139 gfx_color_delete(panel->svc_color);
[8e5f39d]140 panel_clear_entries(panel);
[0e5ed803]141 ui_control_delete(panel->control);
[68b9e540]142 free(panel);
143}
144
[af2ea83]145/** Paint panel entry.
146 *
147 * @param entry Panel entry
148 * @param entry_idx Entry index (within list of entries)
149 * @return EOK on success or an error code
150 */
151errno_t panel_entry_paint(panel_entry_t *entry, size_t entry_idx)
152{
153 panel_t *panel = entry->panel;
154 gfx_context_t *gc = ui_window_get_gc(panel->window);
155 ui_resource_t *res = ui_window_get_res(panel->window);
156 gfx_font_t *font = ui_resource_get_font(res);
157 gfx_text_fmt_t fmt;
158 gfx_coord2_t pos;
159 gfx_rect_t rect;
160 size_t rows;
161 errno_t rc;
162
163 gfx_text_fmt_init(&fmt);
[3e6c51f]164 rows = panel_page_size(panel);
[af2ea83]165
166 /* Do not display entry outside of current page */
167 if (entry_idx < panel->page_idx ||
168 entry_idx >= panel->page_idx + rows)
169 return EOK;
170
171 pos.x = panel->rect.p0.x + 1;
172 pos.y = panel->rect.p0.y + 1 + entry_idx - panel->page_idx;
173
[fe5c7a1]174 if (entry == panel->cursor && panel->active)
[af2ea83]175 fmt.color = panel->curs_color;
[9bed565]176 else if (entry->isdir)
177 fmt.color = panel->dir_color;
[75357c5]178 else if (entry->svc != 0)
179 fmt.color = panel->svc_color;
[af2ea83]180 else
181 fmt.color = panel->color;
182
183 /* Draw entry background */
184 rect.p0 = pos;
185 rect.p1.x = panel->rect.p1.x - 1;
186 rect.p1.y = rect.p0.y + 1;
187
188 rc = gfx_set_color(gc, fmt.color);
189 if (rc != EOK)
190 return rc;
191
192 rc = gfx_fill_rect(gc, &rect);
193 if (rc != EOK)
194 return rc;
195
196 rc = gfx_puttext(font, &pos, &fmt, entry->name);
197 if (rc != EOK)
198 return rc;
199
200 return EOK;
201}
202
[0e5ed803]203/** Paint panel.
204 *
205 * @param panel Panel
206 */
207errno_t panel_paint(panel_t *panel)
208{
209 gfx_context_t *gc = ui_window_get_gc(panel->window);
210 ui_resource_t *res = ui_window_get_res(panel->window);
[8e5f39d]211 gfx_text_fmt_t fmt;
212 panel_entry_t *entry;
[fe5c7a1]213 ui_box_style_t bstyle;
214 gfx_color_t *bcolor;
[af2ea83]215 int i, lines;
[0e5ed803]216 errno_t rc;
217
[8e5f39d]218 gfx_text_fmt_init(&fmt);
219
[0e5ed803]220 rc = gfx_set_color(gc, panel->color);
221 if (rc != EOK)
222 return rc;
223
224 rc = gfx_fill_rect(gc, &panel->rect);
225 if (rc != EOK)
226 return rc;
227
[fe5c7a1]228 if (panel->active) {
229 bstyle = ui_box_double;
230 bcolor = panel->act_border_color;
231 } else {
232 bstyle = ui_box_single;
233 bcolor = panel->color;
234 }
235
236 rc = ui_paint_text_box(res, &panel->rect, bstyle, bcolor);
[0e5ed803]237 if (rc != EOK)
238 return rc;
239
[3e6c51f]240 lines = panel_page_size(panel);
[af2ea83]241 i = 0;
[8e5f39d]242
243 entry = panel->page;
[af2ea83]244 while (entry != NULL && i < lines) {
245 rc = panel_entry_paint(entry, panel->page_idx + i);
[8e5f39d]246 if (rc != EOK)
247 return rc;
248
[af2ea83]249 ++i;
[8e5f39d]250 entry = panel_next(entry);
251 }
252
[0e5ed803]253 rc = gfx_update(gc);
254 if (rc != EOK)
255 return rc;
256
257 return EOK;
258}
259
[af2ea83]260/** Handle panel keyboard event.
261 *
262 * @param panel Panel
263 * @param event Keyboard event
264 * @return ui_claimed iff event was claimed
265 */
266ui_evclaim_t panel_kbd_event(panel_t *panel, kbd_event_t *event)
267{
[fe5c7a1]268 if (!panel->active)
269 return ui_unclaimed;
270
[af2ea83]271 if (event->type == KEY_PRESS) {
272 if ((event->mods & (KM_CTRL | KM_ALT | KM_SHIFT)) == 0) {
273 switch (event->key) {
274 case KC_UP:
275 panel_cursor_up(panel);
276 break;
277 case KC_DOWN:
278 panel_cursor_down(panel);
279 break;
280 case KC_HOME:
281 panel_cursor_top(panel);
282 break;
283 case KC_END:
284 panel_cursor_bottom(panel);
285 break;
[3e6c51f]286 case KC_PAGE_UP:
287 panel_page_up(panel);
288 break;
289 case KC_PAGE_DOWN:
290 panel_page_down(panel);
291 break;
[0e125698]292 case KC_ENTER:
293 panel_open(panel, panel->cursor);
294 break;
[af2ea83]295 default:
296 break;
297 }
298 }
299 }
300
[fe5c7a1]301 return ui_claimed;
[af2ea83]302}
303
[0e5ed803]304/** Handle panel position event.
305 *
306 * @param panel Panel
307 * @param event Position event
308 * @return ui_claimed iff event was claimed
309 */
310ui_evclaim_t panel_pos_event(panel_t *panel, pos_event_t *event)
311{
312 return ui_unclaimed;
313}
314
315/** Get base control for panel.
316 *
317 * @param panel Panel
318 * @return Base UI control
319 */
320ui_control_t *panel_ctl(panel_t *panel)
321{
322 return panel->control;
323}
324
325/** Set panel rectangle.
326 *
327 * @param panel Panel
328 * @param rect Rectangle
329 */
330void panel_set_rect(panel_t *panel, gfx_rect_t *rect)
331{
332 panel->rect = *rect;
333}
334
[3e6c51f]335/** Get panel page size.
336 *
337 * @param panel Panel
338 * @return Number of entries that fit in panel at the same time.
339 */
340unsigned panel_page_size(panel_t *panel)
341{
342 return panel->rect.p1.y - panel->rect.p0.y - 2;
343}
344
[fe5c7a1]345/** Determine if panel is active.
346 *
347 * @param panel Panel
348 * @return @c true iff panel is active
349 */
350bool panel_is_active(panel_t *panel)
351{
352 return panel->active;
353}
354
355/** Activate panel.
356 *
357 * @param panel Panel
[0e125698]358 *
359 * @return EOK on success or an error code
[fe5c7a1]360 */
[0e125698]361errno_t panel_activate(panel_t *panel)
[fe5c7a1]362{
[0e125698]363 errno_t rc;
364
365 if (panel->dir != NULL) {
366 rc = vfs_cwd_set(panel->dir);
367 if (rc != EOK)
368 return rc;
369 }
370
[fe5c7a1]371 panel->active = true;
372 (void) panel_paint(panel);
[0e125698]373 return EOK;
[fe5c7a1]374}
375
376/** Deactivate panel.
377 *
378 * @param panel Panel
379 */
380void panel_deactivate(panel_t *panel)
381{
382 panel->active = false;
383 (void) panel_paint(panel);
384}
385
[75357c5]386/** Initialize panel entry attributes.
387 *
388 * @param attr Attributes
389 */
390void panel_entry_attr_init(panel_entry_attr_t *attr)
391{
392 memset(attr, 0, sizeof(*attr));
393}
394
[0e5ed803]395/** Destroy panel control.
396 *
397 * @param arg Argument (panel_t *)
398 */
399void panel_ctl_destroy(void *arg)
400{
401 panel_t *panel = (panel_t *) arg;
402
403 panel_destroy(panel);
404}
405
406/** Paint panel control.
407 *
408 * @param arg Argument (panel_t *)
409 * @return EOK on success or an error code
410 */
411errno_t panel_ctl_paint(void *arg)
412{
413 panel_t *panel = (panel_t *) arg;
414
415 return panel_paint(panel);
416}
417
[af2ea83]418/** Handle panel control keyboard event.
419 *
420 * @param arg Argument (panel_t *)
421 * @param kbd_event Keyboard event
422 * @return @c ui_claimed iff the event is claimed
423 */
424ui_evclaim_t panel_ctl_kbd_event(void *arg, kbd_event_t *event)
425{
426 panel_t *panel = (panel_t *) arg;
427
428 return panel_kbd_event(panel, event);
429}
430
[0e5ed803]431/** Handle panel control position event.
432 *
433 * @param arg Argument (panel_t *)
434 * @param pos_event Position event
435 * @return @c ui_claimed iff the event is claimed
436 */
437ui_evclaim_t panel_ctl_pos_event(void *arg, pos_event_t *event)
438{
439 panel_t *panel = (panel_t *) arg;
440
441 return panel_pos_event(panel, event);
442}
443
[3b67e95]444/** Append new panel entry.
445 *
446 * @param panel Panel
[75357c5]447 * @param attr Entry attributes
[3b67e95]448 * @return EOK on success or an error code
449 */
[75357c5]450errno_t panel_entry_append(panel_t *panel, panel_entry_attr_t *attr)
[3b67e95]451{
452 panel_entry_t *entry;
453
454 entry = calloc(1, sizeof(panel_entry_t));
455 if (entry == NULL)
456 return ENOMEM;
457
458 entry->panel = panel;
[75357c5]459 entry->name = str_dup(attr->name);
[3b67e95]460 if (entry->name == NULL) {
461 free(entry);
462 return ENOMEM;
463 }
464
[75357c5]465 entry->size = attr->size;
466 entry->isdir = attr->isdir;
467 entry->svc = attr->svc;
[3b67e95]468 link_initialize(&entry->lentries);
469 list_append(&entry->lentries, &panel->entries);
[af2ea83]470 ++panel->entries_cnt;
[3b67e95]471 return EOK;
472}
473
474/** Delete panel entry.
475 *
476 * @param entry Panel entry
477 */
478void panel_entry_delete(panel_entry_t *entry)
479{
[8e5f39d]480 if (entry->panel->cursor == entry)
481 entry->panel->cursor = NULL;
482 if (entry->panel->page == entry)
483 entry->panel->page = NULL;
484
[3b67e95]485 list_remove(&entry->lentries);
[af2ea83]486 --entry->panel->entries_cnt;
[75357c5]487 free((char *) entry->name);
[3b67e95]488 free(entry);
489}
490
[8e5f39d]491/** Clear panel entry list.
492 *
493 * @param panel Panel
494 */
495void panel_clear_entries(panel_t *panel)
496{
497 panel_entry_t *entry;
498
499 entry = panel_first(panel);
500 while (entry != NULL) {
501 panel_entry_delete(entry);
502 entry = panel_first(panel);
503 }
504}
505
506/** Read directory into panel entry list.
507 *
508 * @param panel Panel
509 * @param dirname Directory path
510 * @return EOK on success or an error code
511 */
512errno_t panel_read_dir(panel_t *panel, const char *dirname)
513{
514 DIR *dir;
515 struct dirent *dirent;
[9bed565]516 vfs_stat_t finfo;
[0e125698]517 char newdir[256];
518 char *ndir = NULL;
[75357c5]519 panel_entry_attr_t attr;
[8e5f39d]520 errno_t rc;
521
[0e125698]522 rc = vfs_cwd_set(dirname);
523 if (rc != EOK)
524 return rc;
525
526 rc = vfs_cwd_get(newdir, sizeof(newdir));
527 if (rc != EOK)
528 return rc;
529
530 ndir = str_dup(newdir);
531 if (ndir == NULL)
532 return ENOMEM;
533
534 dir = opendir(".");
535 if (dir == NULL) {
536 rc = errno;
537 goto error;
538 }
539
540 if (str_cmp(ndir, "/") != 0) {
541 /* Need to add a synthetic up-dir entry */
[75357c5]542 panel_entry_attr_init(&attr);
543 attr.name = "..";
544 attr.isdir = true;
545
546 rc = panel_entry_append(panel, &attr);
[0e125698]547 if (rc != EOK)
548 goto error;
549 }
[8e5f39d]550
551 dirent = readdir(dir);
552 while (dirent != NULL) {
[9bed565]553 rc = vfs_stat_path(dirent->d_name, &finfo);
[0e125698]554 if (rc != EOK) {
555 /* Possibly a stale entry */
556 dirent = readdir(dir);
557 continue;
558 }
[9bed565]559
[75357c5]560 panel_entry_attr_init(&attr);
561 attr.name = dirent->d_name;
562 attr.size = finfo.size;
563 attr.isdir = finfo.is_directory;
564 attr.svc = finfo.service;
565
566 rc = panel_entry_append(panel, &attr);
[8e5f39d]567 if (rc != EOK)
568 goto error;
[9bed565]569
[8e5f39d]570 dirent = readdir(dir);
571 }
572
573 closedir(dir);
574
[03c4b23]575 rc = panel_sort(panel);
576 if (rc != EOK)
577 goto error;
578
[8e5f39d]579 panel->cursor = panel_first(panel);
[af2ea83]580 panel->cursor_idx = 0;
[8e5f39d]581 panel->page = panel_first(panel);
[af2ea83]582 panel->page_idx = 0;
[0e125698]583 free(panel->dir);
584 panel->dir = ndir;
[8e5f39d]585 return EOK;
586error:
[0e125698]587 (void) vfs_cwd_set(panel->dir);
588 if (ndir != NULL)
589 free(ndir);
590 if (dir != NULL)
591 closedir(dir);
[8e5f39d]592 return rc;
593}
594
[03c4b23]595/** Sort panel entries.
596 *
597 * @param panel Panel
598 * @return EOK on success, ENOMEM if out of memory
599 */
600errno_t panel_sort(panel_t *panel)
601{
602 panel_entry_t **emap;
603 panel_entry_t *entry;
604 size_t i;
605
606 /* Create an array to hold pointer to each entry */
607 emap = calloc(panel->entries_cnt, sizeof(panel_entry_t *));
608 if (emap == NULL)
609 return ENOMEM;
610
611 /* Write entry pointers to array */
612 entry = panel_first(panel);
613 i = 0;
614 while (entry != NULL) {
615 assert(i < panel->entries_cnt);
616 emap[i++] = entry;
617 entry = panel_next(entry);
618 }
619
620 /* Sort the array of pointers */
621 qsort(emap, panel->entries_cnt, sizeof(panel_entry_t *),
622 panel_entry_ptr_cmp);
623
624 /* Unlink entries from entry list */
625 entry = panel_first(panel);
626 while (entry != NULL) {
627 list_remove(&entry->lentries);
628 entry = panel_first(panel);
629 }
630
631 /* Add entries back to entry list sorted */
632 for (i = 0; i < panel->entries_cnt; i++)
633 list_append(&emap[i]->lentries, &panel->entries);
634
635 free(emap);
636 return EOK;
637}
638
639/** Compare two panel entries indirectly referenced by pointers.
640 *
641 * @param pa Pointer to pointer to first entry
642 * @param pb Pointer to pointer to second entry
643 * @return <0, =0, >=0 if pa < b, pa == pb, pa > pb, resp.
644 */
645int panel_entry_ptr_cmp(const void *pa, const void *pb)
646{
647 panel_entry_t *a = *(panel_entry_t **)pa;
648 panel_entry_t *b = *(panel_entry_t **)pb;
[9bed565]649 int dcmp;
650
651 /* Sort directories first */
652 dcmp = b->isdir - a->isdir;
653 if (dcmp != 0)
654 return dcmp;
[03c4b23]655
656 return str_cmp(a->name, b->name);
657}
658
[3b67e95]659/** Return first panel entry.
660 *
661 * @panel Panel
662 * @return First panel entry or @c NULL if there are no entries
663 */
664panel_entry_t *panel_first(panel_t *panel)
665{
666 link_t *link;
667
668 link = list_first(&panel->entries);
669 if (link == NULL)
670 return NULL;
671
672 return list_get_instance(link, panel_entry_t, lentries);
673}
674
[af2ea83]675/** Return last panel entry.
676 *
677 * @panel Panel
678 * @return Last panel entry or @c NULL if there are no entries
679 */
680panel_entry_t *panel_last(panel_t *panel)
681{
682 link_t *link;
683
684 link = list_last(&panel->entries);
685 if (link == NULL)
686 return NULL;
687
688 return list_get_instance(link, panel_entry_t, lentries);
689}
690
[3b67e95]691/** Return next panel entry.
692 *
693 * @param cur Current entry
694 * @return Next entry or @c NULL if @a cur is the last entry
695 */
696panel_entry_t *panel_next(panel_entry_t *cur)
697{
698 link_t *link;
699
700 link = list_next(&cur->lentries, &cur->panel->entries);
701 if (link == NULL)
702 return NULL;
703
704 return list_get_instance(link, panel_entry_t, lentries);
705}
[0e5ed803]706
[af2ea83]707/** Return previous panel entry.
708 *
709 * @param cur Current entry
710 * @return Previous entry or @c NULL if @a cur is the first entry
711 */
712panel_entry_t *panel_prev(panel_entry_t *cur)
713{
714 link_t *link;
715
716 link = list_prev(&cur->lentries, &cur->panel->entries);
717 if (link == NULL)
718 return NULL;
719
720 return list_get_instance(link, panel_entry_t, lentries);
721}
722
[3e6c51f]723/** Move cursor to a new position, possibly scrolling.
724 *
725 * @param panel Panel
726 * @param entry New entry under cursor
727 * @param entry_idx Index of new entry under cursor
728 */
[af2ea83]729void panel_cursor_move(panel_t *panel, panel_entry_t *entry, size_t entry_idx)
730{
731 gfx_context_t *gc = ui_window_get_gc(panel->window);
732 panel_entry_t *old_cursor;
733 size_t old_idx;
734 size_t rows;
735 panel_entry_t *e;
736 size_t i;
737
[3e6c51f]738 rows = panel_page_size(panel);
[af2ea83]739
740 old_cursor = panel->cursor;
741 old_idx = panel->cursor_idx;
742
743 panel->cursor = entry;
744 panel->cursor_idx = entry_idx;
745
746 if (entry_idx >= panel->page_idx &&
747 entry_idx < panel->page_idx + rows) {
748 /*
749 * If cursor is still on the current page, we're not
750 * scrolling. Just unpaint old cursor and paint new
751 * cursor.
752 */
753 panel_entry_paint(old_cursor, old_idx);
754 panel_entry_paint(panel->cursor, panel->cursor_idx);
755
756 (void) gfx_update(gc);
757 } else {
758 /*
759 * Need to scroll and update all rows.
760 */
761
762 /* Scrolling up */
763 if (entry_idx < panel->page_idx) {
764 panel->page = entry;
765 panel->page_idx = entry_idx;
766 }
767
768 /* Scrolling down */
769 if (entry_idx >= panel->page_idx + rows) {
770 if (entry_idx >= rows) {
771 panel->page_idx = entry_idx - rows + 1;
772 /* Find first page entry (go back rows - 1) */
773 e = entry;
774 for (i = 0; i < rows - 1; i++) {
775 e = panel_prev(e);
776 }
777
778 /* Should be valid */
779 assert(e != NULL);
780 panel->page = e;
781 } else {
782 panel->page = panel_first(panel);
783 panel->page_idx = 0;
784 }
785 }
786
787 (void) panel_paint(panel);
788 }
789}
790
791/** Move cursor one entry up.
792 *
793 * @param panel Panel
794 */
795void panel_cursor_up(panel_t *panel)
796{
797 panel_entry_t *prev;
798 size_t prev_idx;
799
800 prev = panel_prev(panel->cursor);
801 prev_idx = panel->cursor_idx - 1;
802 if (prev != NULL)
803 panel_cursor_move(panel, prev, prev_idx);
804}
805
806/** Move cursor one entry down.
807 *
808 * @param panel Panel
809 */
810void panel_cursor_down(panel_t *panel)
811{
812 panel_entry_t *next;
813 size_t next_idx;
814
815 next = panel_next(panel->cursor);
816 next_idx = panel->cursor_idx + 1;
817 if (next != NULL)
818 panel_cursor_move(panel, next, next_idx);
819}
820
821/** Move cursor to top.
822 *
823 * @param panel Panel
824 */
825void panel_cursor_top(panel_t *panel)
826{
827 panel_cursor_move(panel, panel_first(panel), 0);
828}
829
830/** Move cursor to bottom.
831 *
832 * @param panel Panel
833 */
834void panel_cursor_bottom(panel_t *panel)
835{
836 panel_cursor_move(panel, panel_last(panel), panel->entries_cnt - 1);
837}
838
[3e6c51f]839/** Move one page up.
840 *
841 * @param panel Panel
842 */
843void panel_page_up(panel_t *panel)
844{
845 gfx_context_t *gc = ui_window_get_gc(panel->window);
846 panel_entry_t *old_page;
847 panel_entry_t *old_cursor;
848 size_t old_idx;
849 size_t rows;
850 panel_entry_t *entry;
851 size_t i;
852
853 rows = panel_page_size(panel);
854
855 old_page = panel->page;
856 old_cursor = panel->cursor;
857 old_idx = panel->cursor_idx;
858
859 /* Move page by rows entries up (if possible) */
860 for (i = 0; i < rows; i++) {
861 entry = panel_prev(panel->page);
862 if (entry != NULL) {
863 panel->page = entry;
864 --panel->page_idx;
865 }
866 }
867
868 /* Move cursor by rows entries up (if possible) */
869
870 for (i = 0; i < rows; i++) {
871 entry = panel_prev(panel->cursor);
872 if (entry != NULL) {
873 panel->cursor = entry;
874 --panel->cursor_idx;
875 }
876 }
877
878 if (panel->page != old_page) {
879 /* We have scrolled. Need to repaint all entries */
880 (void) panel_paint(panel);
881 } else if (panel->cursor != old_cursor) {
882 /* No scrolling, but cursor has moved */
883 panel_entry_paint(old_cursor, old_idx);
884 panel_entry_paint(panel->cursor, panel->cursor_idx);
885
886 (void) gfx_update(gc);
887 }
888}
889
890/** Move one page down.
891 *
892 * @param panel Panel
893 */
894void panel_page_down(panel_t *panel)
895{
896 gfx_context_t *gc = ui_window_get_gc(panel->window);
897 panel_entry_t *old_page;
898 panel_entry_t *old_cursor;
899 size_t old_idx;
900 size_t max_idx;
901 size_t rows;
902 panel_entry_t *entry;
903 size_t i;
904
905 rows = panel_page_size(panel);
906
907 old_page = panel->page;
908 old_cursor = panel->cursor;
909 old_idx = panel->cursor_idx;
910 max_idx = panel->entries_cnt - rows;
911
912 /* Move page by rows entries down (if possible) */
913 for (i = 0; i < rows; i++) {
914 entry = panel_next(panel->page);
915 /* Do not scroll that results in a short page */
916 if (entry != NULL && panel->page_idx < max_idx) {
917 panel->page = entry;
918 ++panel->page_idx;
919 }
920 }
921
922 /* Move cursor by rows entries down (if possible) */
923
924 for (i = 0; i < rows; i++) {
925 entry = panel_next(panel->cursor);
926 if (entry != NULL) {
927 panel->cursor = entry;
928 ++panel->cursor_idx;
929 }
930 }
931
932 if (panel->page != old_page) {
933 /* We have scrolled. Need to repaint all entries */
934 (void) panel_paint(panel);
935 } else if (panel->cursor != old_cursor) {
936 /* No scrolling, but cursor has moved */
937 panel_entry_paint(old_cursor, old_idx);
938 panel_entry_paint(panel->cursor, panel->cursor_idx);
939
940 (void) gfx_update(gc);
941 }
942}
943
[0e125698]944/** Open panel entry.
945 *
946 * Perform Open action on a panel entry (e.g. switch to a subdirectory).
947 *
948 * @param panel Panel
949 * @param entry Panel entry
950 *
951 * @return EOK on success or an error code
952 */
953errno_t panel_open(panel_t *panel, panel_entry_t *entry)
954{
955 gfx_context_t *gc = ui_window_get_gc(panel->window);
956 char *dirname;
957 errno_t rc;
958
959 if (!entry->isdir)
960 return EOK;
961
962 dirname = str_dup(entry->name);
963 panel_clear_entries(panel);
964
965 rc = panel_read_dir(panel, dirname);
966 if (rc != EOK) {
967 free(dirname);
968 return rc;
969 }
970
971 rc = panel_paint(panel);
972 if (rc != EOK) {
973 free(dirname);
974 return rc;
975 }
976
977 free(dirname);
978 return gfx_update(gc);
979}
980
[68b9e540]981/** @}
982 */
Note: See TracBrowser for help on using the repository browser.