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
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 rc = gfx_color_new_ega(0x0a, &panel->svc_color);
104 if (rc != EOK)
105 goto error;
106
107 panel->window = window;
108 list_initialize(&panel->entries);
109 panel->entries_cnt = 0;
110 panel->active = active;
111 *rpanel = panel;
112 return EOK;
113error:
114 if (panel->color != NULL)
115 gfx_color_delete(panel->color);
116 if (panel->curs_color != NULL)
117 gfx_color_delete(panel->curs_color);
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);
122 if (panel->svc_color != NULL)
123 gfx_color_delete(panel->svc_color);
124 ui_control_delete(panel->control);
125 free(panel);
126 return rc;
127}
128
129/** Destroy panel.
130 *
131 * @param panel Panel
132 */
133void panel_destroy(panel_t *panel)
134{
135 gfx_color_delete(panel->color);
136 gfx_color_delete(panel->curs_color);
137 gfx_color_delete(panel->act_border_color);
138 gfx_color_delete(panel->dir_color);
139 gfx_color_delete(panel->svc_color);
140 panel_clear_entries(panel);
141 ui_control_delete(panel->control);
142 free(panel);
143}
144
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);
164 rows = panel_page_size(panel);
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
174 if (entry == panel->cursor && panel->active)
175 fmt.color = panel->curs_color;
176 else if (entry->isdir)
177 fmt.color = panel->dir_color;
178 else if (entry->svc != 0)
179 fmt.color = panel->svc_color;
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
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);
211 gfx_text_fmt_t fmt;
212 panel_entry_t *entry;
213 ui_box_style_t bstyle;
214 gfx_color_t *bcolor;
215 int i, lines;
216 errno_t rc;
217
218 gfx_text_fmt_init(&fmt);
219
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
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);
237 if (rc != EOK)
238 return rc;
239
240 lines = panel_page_size(panel);
241 i = 0;
242
243 entry = panel->page;
244 while (entry != NULL && i < lines) {
245 rc = panel_entry_paint(entry, panel->page_idx + i);
246 if (rc != EOK)
247 return rc;
248
249 ++i;
250 entry = panel_next(entry);
251 }
252
253 rc = gfx_update(gc);
254 if (rc != EOK)
255 return rc;
256
257 return EOK;
258}
259
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{
268 if (!panel->active)
269 return ui_unclaimed;
270
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;
286 case KC_PAGE_UP:
287 panel_page_up(panel);
288 break;
289 case KC_PAGE_DOWN:
290 panel_page_down(panel);
291 break;
292 case KC_ENTER:
293 panel_open(panel, panel->cursor);
294 break;
295 default:
296 break;
297 }
298 }
299 }
300
301 return ui_claimed;
302}
303
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
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
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
358 *
359 * @return EOK on success or an error code
360 */
361errno_t panel_activate(panel_t *panel)
362{
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
371 panel->active = true;
372 (void) panel_paint(panel);
373 return EOK;
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
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
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
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
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
444/** Append new panel entry.
445 *
446 * @param panel Panel
447 * @param attr Entry attributes
448 * @return EOK on success or an error code
449 */
450errno_t panel_entry_append(panel_t *panel, panel_entry_attr_t *attr)
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;
459 entry->name = str_dup(attr->name);
460 if (entry->name == NULL) {
461 free(entry);
462 return ENOMEM;
463 }
464
465 entry->size = attr->size;
466 entry->isdir = attr->isdir;
467 entry->svc = attr->svc;
468 link_initialize(&entry->lentries);
469 list_append(&entry->lentries, &panel->entries);
470 ++panel->entries_cnt;
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{
480 if (entry->panel->cursor == entry)
481 entry->panel->cursor = NULL;
482 if (entry->panel->page == entry)
483 entry->panel->page = NULL;
484
485 list_remove(&entry->lentries);
486 --entry->panel->entries_cnt;
487 free((char *) entry->name);
488 free(entry);
489}
490
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;
516 vfs_stat_t finfo;
517 char newdir[256];
518 char *ndir = NULL;
519 panel_entry_attr_t attr;
520 errno_t rc;
521
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 */
542 panel_entry_attr_init(&attr);
543 attr.name = "..";
544 attr.isdir = true;
545
546 rc = panel_entry_append(panel, &attr);
547 if (rc != EOK)
548 goto error;
549 }
550
551 dirent = readdir(dir);
552 while (dirent != NULL) {
553 rc = vfs_stat_path(dirent->d_name, &finfo);
554 if (rc != EOK) {
555 /* Possibly a stale entry */
556 dirent = readdir(dir);
557 continue;
558 }
559
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);
567 if (rc != EOK)
568 goto error;
569
570 dirent = readdir(dir);
571 }
572
573 closedir(dir);
574
575 rc = panel_sort(panel);
576 if (rc != EOK)
577 goto error;
578
579 panel->cursor = panel_first(panel);
580 panel->cursor_idx = 0;
581 panel->page = panel_first(panel);
582 panel->page_idx = 0;
583 free(panel->dir);
584 panel->dir = ndir;
585 return EOK;
586error:
587 (void) vfs_cwd_set(panel->dir);
588 if (ndir != NULL)
589 free(ndir);
590 if (dir != NULL)
591 closedir(dir);
592 return rc;
593}
594
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;
649 int dcmp;
650
651 /* Sort directories first */
652 dcmp = b->isdir - a->isdir;
653 if (dcmp != 0)
654 return dcmp;
655
656 return str_cmp(a->name, b->name);
657}
658
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
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
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}
706
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
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 */
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
738 rows = panel_page_size(panel);
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
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
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
981/** @}
982 */
Note: See TracBrowser for help on using the repository browser.