source: mainline/uspace/app/nav/panel.c@ fd6dc08

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

Opening directories

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