source: mainline/uspace/app/nav/panel.c@ 2651dc5

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

Unmap and clear console before executing a binary

Fixes running edit, nav, improves fdisk, etc.

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