source: mainline/uspace/app/nav/panel.c@ 01e9991

serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 01e9991 was 01e9991, checked in by jxsvoboda <5887334+jxsvoboda@…>, 4 years ago

Executing binaries

  • Property mode set to 100644
File size: 21.5 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 errno_t rc;
522
523 rc = vfs_cwd_set(dirname);
524 if (rc != EOK)
525 return rc;
526
527 rc = vfs_cwd_get(newdir, sizeof(newdir));
528 if (rc != EOK)
529 return rc;
530
531 ndir = str_dup(newdir);
532 if (ndir == NULL)
533 return ENOMEM;
534
535 dir = opendir(".");
536 if (dir == NULL) {
537 rc = errno;
538 goto error;
539 }
540
541 if (str_cmp(ndir, "/") != 0) {
542 /* Need to add a synthetic up-dir entry */
543 panel_entry_attr_init(&attr);
544 attr.name = "..";
545 attr.isdir = true;
546
547 rc = panel_entry_append(panel, &attr);
548 if (rc != EOK)
549 goto error;
550 }
551
552 dirent = readdir(dir);
553 while (dirent != NULL) {
554 rc = vfs_stat_path(dirent->d_name, &finfo);
555 if (rc != EOK) {
556 /* Possibly a stale entry */
557 dirent = readdir(dir);
558 continue;
559 }
560
561 panel_entry_attr_init(&attr);
562 attr.name = dirent->d_name;
563 attr.size = finfo.size;
564 attr.isdir = finfo.is_directory;
565 attr.svc = finfo.service;
566
567 rc = panel_entry_append(panel, &attr);
568 if (rc != EOK)
569 goto error;
570
571 dirent = readdir(dir);
572 }
573
574 closedir(dir);
575
576 rc = panel_sort(panel);
577 if (rc != EOK)
578 goto error;
579
580 panel->cursor = panel_first(panel);
581 panel->cursor_idx = 0;
582 panel->page = panel_first(panel);
583 panel->page_idx = 0;
584 free(panel->dir);
585 panel->dir = ndir;
586 return EOK;
587error:
588 (void) vfs_cwd_set(panel->dir);
589 if (ndir != NULL)
590 free(ndir);
591 if (dir != NULL)
592 closedir(dir);
593 return rc;
594}
595
596/** Sort panel entries.
597 *
598 * @param panel Panel
599 * @return EOK on success, ENOMEM if out of memory
600 */
601errno_t panel_sort(panel_t *panel)
602{
603 panel_entry_t **emap;
604 panel_entry_t *entry;
605 size_t i;
606
607 /* Create an array to hold pointer to each entry */
608 emap = calloc(panel->entries_cnt, sizeof(panel_entry_t *));
609 if (emap == NULL)
610 return ENOMEM;
611
612 /* Write entry pointers to array */
613 entry = panel_first(panel);
614 i = 0;
615 while (entry != NULL) {
616 assert(i < panel->entries_cnt);
617 emap[i++] = entry;
618 entry = panel_next(entry);
619 }
620
621 /* Sort the array of pointers */
622 qsort(emap, panel->entries_cnt, sizeof(panel_entry_t *),
623 panel_entry_ptr_cmp);
624
625 /* Unlink entries from entry list */
626 entry = panel_first(panel);
627 while (entry != NULL) {
628 list_remove(&entry->lentries);
629 entry = panel_first(panel);
630 }
631
632 /* Add entries back to entry list sorted */
633 for (i = 0; i < panel->entries_cnt; i++)
634 list_append(&emap[i]->lentries, &panel->entries);
635
636 free(emap);
637 return EOK;
638}
639
640/** Compare two panel entries indirectly referenced by pointers.
641 *
642 * @param pa Pointer to pointer to first entry
643 * @param pb Pointer to pointer to second entry
644 * @return <0, =0, >=0 if pa < b, pa == pb, pa > pb, resp.
645 */
646int panel_entry_ptr_cmp(const void *pa, const void *pb)
647{
648 panel_entry_t *a = *(panel_entry_t **)pa;
649 panel_entry_t *b = *(panel_entry_t **)pb;
650 int dcmp;
651
652 /* Sort directories first */
653 dcmp = b->isdir - a->isdir;
654 if (dcmp != 0)
655 return dcmp;
656
657 return str_cmp(a->name, b->name);
658}
659
660/** Return first panel entry.
661 *
662 * @panel Panel
663 * @return First panel entry or @c NULL if there are no entries
664 */
665panel_entry_t *panel_first(panel_t *panel)
666{
667 link_t *link;
668
669 link = list_first(&panel->entries);
670 if (link == NULL)
671 return NULL;
672
673 return list_get_instance(link, panel_entry_t, lentries);
674}
675
676/** Return last panel entry.
677 *
678 * @panel Panel
679 * @return Last panel entry or @c NULL if there are no entries
680 */
681panel_entry_t *panel_last(panel_t *panel)
682{
683 link_t *link;
684
685 link = list_last(&panel->entries);
686 if (link == NULL)
687 return NULL;
688
689 return list_get_instance(link, panel_entry_t, lentries);
690}
691
692/** Return next panel entry.
693 *
694 * @param cur Current entry
695 * @return Next entry or @c NULL if @a cur is the last entry
696 */
697panel_entry_t *panel_next(panel_entry_t *cur)
698{
699 link_t *link;
700
701 link = list_next(&cur->lentries, &cur->panel->entries);
702 if (link == NULL)
703 return NULL;
704
705 return list_get_instance(link, panel_entry_t, lentries);
706}
707
708/** Return previous panel entry.
709 *
710 * @param cur Current entry
711 * @return Previous entry or @c NULL if @a cur is the first entry
712 */
713panel_entry_t *panel_prev(panel_entry_t *cur)
714{
715 link_t *link;
716
717 link = list_prev(&cur->lentries, &cur->panel->entries);
718 if (link == NULL)
719 return NULL;
720
721 return list_get_instance(link, panel_entry_t, lentries);
722}
723
724/** Move cursor to a new position, possibly scrolling.
725 *
726 * @param panel Panel
727 * @param entry New entry under cursor
728 * @param entry_idx Index of new entry under cursor
729 */
730void panel_cursor_move(panel_t *panel, panel_entry_t *entry, size_t entry_idx)
731{
732 gfx_context_t *gc = ui_window_get_gc(panel->window);
733 panel_entry_t *old_cursor;
734 size_t old_idx;
735 size_t rows;
736 panel_entry_t *e;
737 size_t i;
738
739 rows = panel_page_size(panel);
740
741 old_cursor = panel->cursor;
742 old_idx = panel->cursor_idx;
743
744 panel->cursor = entry;
745 panel->cursor_idx = entry_idx;
746
747 if (entry_idx >= panel->page_idx &&
748 entry_idx < panel->page_idx + rows) {
749 /*
750 * If cursor is still on the current page, we're not
751 * scrolling. Just unpaint old cursor and paint new
752 * cursor.
753 */
754 panel_entry_paint(old_cursor, old_idx);
755 panel_entry_paint(panel->cursor, panel->cursor_idx);
756
757 (void) gfx_update(gc);
758 } else {
759 /*
760 * Need to scroll and update all rows.
761 */
762
763 /* Scrolling up */
764 if (entry_idx < panel->page_idx) {
765 panel->page = entry;
766 panel->page_idx = entry_idx;
767 }
768
769 /* Scrolling down */
770 if (entry_idx >= panel->page_idx + rows) {
771 if (entry_idx >= rows) {
772 panel->page_idx = entry_idx - rows + 1;
773 /* Find first page entry (go back rows - 1) */
774 e = entry;
775 for (i = 0; i < rows - 1; i++) {
776 e = panel_prev(e);
777 }
778
779 /* Should be valid */
780 assert(e != NULL);
781 panel->page = e;
782 } else {
783 panel->page = panel_first(panel);
784 panel->page_idx = 0;
785 }
786 }
787
788 (void) panel_paint(panel);
789 }
790}
791
792/** Move cursor one entry up.
793 *
794 * @param panel Panel
795 */
796void panel_cursor_up(panel_t *panel)
797{
798 panel_entry_t *prev;
799 size_t prev_idx;
800
801 prev = panel_prev(panel->cursor);
802 prev_idx = panel->cursor_idx - 1;
803 if (prev != NULL)
804 panel_cursor_move(panel, prev, prev_idx);
805}
806
807/** Move cursor one entry down.
808 *
809 * @param panel Panel
810 */
811void panel_cursor_down(panel_t *panel)
812{
813 panel_entry_t *next;
814 size_t next_idx;
815
816 next = panel_next(panel->cursor);
817 next_idx = panel->cursor_idx + 1;
818 if (next != NULL)
819 panel_cursor_move(panel, next, next_idx);
820}
821
822/** Move cursor to top.
823 *
824 * @param panel Panel
825 */
826void panel_cursor_top(panel_t *panel)
827{
828 panel_cursor_move(panel, panel_first(panel), 0);
829}
830
831/** Move cursor to bottom.
832 *
833 * @param panel Panel
834 */
835void panel_cursor_bottom(panel_t *panel)
836{
837 panel_cursor_move(panel, panel_last(panel), panel->entries_cnt - 1);
838}
839
840/** Move one page up.
841 *
842 * @param panel Panel
843 */
844void panel_page_up(panel_t *panel)
845{
846 gfx_context_t *gc = ui_window_get_gc(panel->window);
847 panel_entry_t *old_page;
848 panel_entry_t *old_cursor;
849 size_t old_idx;
850 size_t rows;
851 panel_entry_t *entry;
852 size_t i;
853
854 rows = panel_page_size(panel);
855
856 old_page = panel->page;
857 old_cursor = panel->cursor;
858 old_idx = panel->cursor_idx;
859
860 /* Move page by rows entries up (if possible) */
861 for (i = 0; i < rows; i++) {
862 entry = panel_prev(panel->page);
863 if (entry != NULL) {
864 panel->page = entry;
865 --panel->page_idx;
866 }
867 }
868
869 /* Move cursor by rows entries up (if possible) */
870
871 for (i = 0; i < rows; i++) {
872 entry = panel_prev(panel->cursor);
873 if (entry != NULL) {
874 panel->cursor = entry;
875 --panel->cursor_idx;
876 }
877 }
878
879 if (panel->page != old_page) {
880 /* We have scrolled. Need to repaint all entries */
881 (void) panel_paint(panel);
882 } else if (panel->cursor != old_cursor) {
883 /* No scrolling, but cursor has moved */
884 panel_entry_paint(old_cursor, old_idx);
885 panel_entry_paint(panel->cursor, panel->cursor_idx);
886
887 (void) gfx_update(gc);
888 }
889}
890
891/** Move one page down.
892 *
893 * @param panel Panel
894 */
895void panel_page_down(panel_t *panel)
896{
897 gfx_context_t *gc = ui_window_get_gc(panel->window);
898 panel_entry_t *old_page;
899 panel_entry_t *old_cursor;
900 size_t old_idx;
901 size_t max_idx;
902 size_t rows;
903 panel_entry_t *entry;
904 size_t i;
905
906 rows = panel_page_size(panel);
907
908 old_page = panel->page;
909 old_cursor = panel->cursor;
910 old_idx = panel->cursor_idx;
911 max_idx = panel->entries_cnt - rows;
912
913 /* Move page by rows entries down (if possible) */
914 for (i = 0; i < rows; i++) {
915 entry = panel_next(panel->page);
916 /* Do not scroll that results in a short page */
917 if (entry != NULL && panel->page_idx < max_idx) {
918 panel->page = entry;
919 ++panel->page_idx;
920 }
921 }
922
923 /* Move cursor by rows entries down (if possible) */
924
925 for (i = 0; i < rows; i++) {
926 entry = panel_next(panel->cursor);
927 if (entry != NULL) {
928 panel->cursor = entry;
929 ++panel->cursor_idx;
930 }
931 }
932
933 if (panel->page != old_page) {
934 /* We have scrolled. Need to repaint all entries */
935 (void) panel_paint(panel);
936 } else if (panel->cursor != old_cursor) {
937 /* No scrolling, but cursor has moved */
938 panel_entry_paint(old_cursor, old_idx);
939 panel_entry_paint(panel->cursor, panel->cursor_idx);
940
941 (void) gfx_update(gc);
942 }
943}
944
945/** Open panel entry.
946 *
947 * Perform Open action on a panel entry (e.g. switch to a subdirectory).
948 *
949 * @param panel Panel
950 * @param entry Panel entry
951 *
952 * @return EOK on success or an error code
953 */
954errno_t panel_open(panel_t *panel, panel_entry_t *entry)
955{
956 if (entry->isdir)
957 return panel_open_dir(panel, entry);
958 else if (entry->svc == 0)
959 return panel_open_file(panel, entry);
960 else
961 return EOK;
962}
963
964/** Open panel directory entry.
965 *
966 * Perform Open action on a directory entry (i.e. switch to the directory).
967 *
968 * @param panel Panel
969 * @param entry Panel entry (which is a directory)
970 *
971 * @return EOK on success or an error code
972 */
973errno_t panel_open_dir(panel_t *panel, panel_entry_t *entry)
974{
975 gfx_context_t *gc = ui_window_get_gc(panel->window);
976 errno_t rc;
977
978 assert(entry->isdir);
979
980 panel_clear_entries(panel);
981
982 rc = panel_read_dir(panel, entry->name);
983 if (rc != EOK)
984 return rc;
985
986 rc = panel_paint(panel);
987 if (rc != EOK)
988 return rc;
989
990 return gfx_update(gc);
991}
992
993/** Open panel file entry.
994 *
995 * Perform Open action on a file entry (i.e. try running it).
996 *
997 * @param panel Panel
998 * @param entry Panel entry (which is a file)
999 *
1000 * @return EOK on success or an error code
1001 */
1002errno_t panel_open_file(panel_t *panel, panel_entry_t *entry)
1003{
1004 task_id_t id;
1005 task_wait_t wait;
1006 task_exit_t texit;
1007 int retval;
1008 errno_t rc;
1009
1010 /* It's not a directory */
1011 assert(!entry->isdir);
1012 /* It's not a service-special file */
1013 assert(entry->svc == 0);
1014
1015 rc = task_spawnl(&id, &wait, entry->name, entry->name, NULL);
1016 if (rc != EOK)
1017 return rc;
1018
1019 rc = task_wait(&wait, &texit, &retval);
1020 if ((rc != EOK) || (texit != TASK_EXIT_NORMAL))
1021 return rc;
1022
1023 (void) ui_paint(ui_window_get_ui(panel->window));
1024 return EOK;
1025}
1026
1027/** @}
1028 */
Note: See TracBrowser for help on using the repository browser.