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
RevLine 
[6aa85c1]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
[0e80e40]37#include <dirent.h>
[6aa85c1]38#include <errno.h>
[b36ebb42]39#include <gfx/render.h>
[0e80e40]40#include <gfx/text.h>
[6aa85c1]41#include <stdlib.h>
[61784ed]42#include <str.h>
[01e9991]43#include <task.h>
[b36ebb42]44#include <ui/control.h>
45#include <ui/paint.h>
[0e80e40]46#include <ui/resource.h>
[fa792e8]47#include <vfs/vfs.h>
[1eb0fafe]48#include <qsort.h>
[6aa85c1]49#include "panel.h"
50#include "nav.h"
51
[b36ebb42]52static void panel_ctl_destroy(void *);
53static errno_t panel_ctl_paint(void *);
[be1d74c1]54static ui_evclaim_t panel_ctl_kbd_event(void *, kbd_event_t *);
[b36ebb42]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,
[be1d74c1]61 .kbd_event = panel_ctl_kbd_event,
[b36ebb42]62 .pos_event = panel_ctl_pos_event
63};
64
[6aa85c1]65/** Create panel.
66 *
[b36ebb42]67 * @param window Containing window
[692c7f40]68 * @param active @c true iff panel should be active
[6aa85c1]69 * @param rpanel Place to store pointer to new panel
70 * @return EOK on success or an error code
71 */
[692c7f40]72errno_t panel_create(ui_window_t *window, bool active, panel_t **rpanel)
[6aa85c1]73{
74 panel_t *panel;
[b36ebb42]75 errno_t rc;
[6aa85c1]76
77 panel = calloc(1, sizeof(panel_t));
78 if (panel == NULL)
79 return ENOMEM;
80
[b36ebb42]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
[0e80e40]92 rc = gfx_color_new_ega(0x30, &panel->curs_color);
93 if (rc != EOK)
94 goto error;
95
[692c7f40]96 rc = gfx_color_new_ega(0x0f, &panel->act_border_color);
97 if (rc != EOK)
98 goto error;
99
[fa792e8]100 rc = gfx_color_new_ega(0x0f, &panel->dir_color);
101 if (rc != EOK)
102 goto error;
103
[7aeb52cb]104 rc = gfx_color_new_ega(0x0a, &panel->svc_color);
105 if (rc != EOK)
106 goto error;
107
[b36ebb42]108 panel->window = window;
[61784ed]109 list_initialize(&panel->entries);
[be1d74c1]110 panel->entries_cnt = 0;
[692c7f40]111 panel->active = active;
[6aa85c1]112 *rpanel = panel;
113 return EOK;
[b36ebb42]114error:
[0e80e40]115 if (panel->color != NULL)
116 gfx_color_delete(panel->color);
117 if (panel->curs_color != NULL)
118 gfx_color_delete(panel->curs_color);
[fa792e8]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);
[7aeb52cb]123 if (panel->svc_color != NULL)
124 gfx_color_delete(panel->svc_color);
[b36ebb42]125 ui_control_delete(panel->control);
126 free(panel);
127 return rc;
[6aa85c1]128}
129
130/** Destroy panel.
131 *
132 * @param panel Panel
133 */
134void panel_destroy(panel_t *panel)
135{
[0e80e40]136 gfx_color_delete(panel->color);
137 gfx_color_delete(panel->curs_color);
[692c7f40]138 gfx_color_delete(panel->act_border_color);
[fa792e8]139 gfx_color_delete(panel->dir_color);
[7aeb52cb]140 gfx_color_delete(panel->svc_color);
[0e80e40]141 panel_clear_entries(panel);
[b36ebb42]142 ui_control_delete(panel->control);
[6aa85c1]143 free(panel);
144}
145
[be1d74c1]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);
[8c72f533]165 rows = panel_page_size(panel);
[be1d74c1]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
[692c7f40]175 if (entry == panel->cursor && panel->active)
[be1d74c1]176 fmt.color = panel->curs_color;
[fa792e8]177 else if (entry->isdir)
178 fmt.color = panel->dir_color;
[7aeb52cb]179 else if (entry->svc != 0)
180 fmt.color = panel->svc_color;
[be1d74c1]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
[b36ebb42]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);
[0e80e40]212 gfx_text_fmt_t fmt;
213 panel_entry_t *entry;
[692c7f40]214 ui_box_style_t bstyle;
215 gfx_color_t *bcolor;
[be1d74c1]216 int i, lines;
[b36ebb42]217 errno_t rc;
218
[0e80e40]219 gfx_text_fmt_init(&fmt);
220
[b36ebb42]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
[692c7f40]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);
[b36ebb42]238 if (rc != EOK)
239 return rc;
240
[8c72f533]241 lines = panel_page_size(panel);
[be1d74c1]242 i = 0;
[0e80e40]243
244 entry = panel->page;
[be1d74c1]245 while (entry != NULL && i < lines) {
246 rc = panel_entry_paint(entry, panel->page_idx + i);
[0e80e40]247 if (rc != EOK)
248 return rc;
249
[be1d74c1]250 ++i;
[0e80e40]251 entry = panel_next(entry);
252 }
253
[b36ebb42]254 rc = gfx_update(gc);
255 if (rc != EOK)
256 return rc;
257
258 return EOK;
259}
260
[be1d74c1]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{
[692c7f40]269 if (!panel->active)
270 return ui_unclaimed;
271
[be1d74c1]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;
[8c72f533]287 case KC_PAGE_UP:
288 panel_page_up(panel);
289 break;
290 case KC_PAGE_DOWN:
291 panel_page_down(panel);
292 break;
[4fcc2de]293 case KC_ENTER:
294 panel_open(panel, panel->cursor);
295 break;
[be1d74c1]296 default:
297 break;
298 }
299 }
300 }
301
[692c7f40]302 return ui_claimed;
[be1d74c1]303}
304
[b36ebb42]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
[8c72f533]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
[692c7f40]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
[4fcc2de]359 *
360 * @return EOK on success or an error code
[692c7f40]361 */
[4fcc2de]362errno_t panel_activate(panel_t *panel)
[692c7f40]363{
[4fcc2de]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
[692c7f40]372 panel->active = true;
373 (void) panel_paint(panel);
[4fcc2de]374 return EOK;
[692c7f40]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
[7aeb52cb]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
[b36ebb42]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
[be1d74c1]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
[b36ebb42]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
[61784ed]445/** Append new panel entry.
446 *
447 * @param panel Panel
[7aeb52cb]448 * @param attr Entry attributes
[61784ed]449 * @return EOK on success or an error code
450 */
[7aeb52cb]451errno_t panel_entry_append(panel_t *panel, panel_entry_attr_t *attr)
[61784ed]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;
[7aeb52cb]460 entry->name = str_dup(attr->name);
[61784ed]461 if (entry->name == NULL) {
462 free(entry);
463 return ENOMEM;
464 }
465
[7aeb52cb]466 entry->size = attr->size;
467 entry->isdir = attr->isdir;
468 entry->svc = attr->svc;
[61784ed]469 link_initialize(&entry->lentries);
470 list_append(&entry->lentries, &panel->entries);
[be1d74c1]471 ++panel->entries_cnt;
[61784ed]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{
[0e80e40]481 if (entry->panel->cursor == entry)
482 entry->panel->cursor = NULL;
483 if (entry->panel->page == entry)
484 entry->panel->page = NULL;
485
[61784ed]486 list_remove(&entry->lentries);
[be1d74c1]487 --entry->panel->entries_cnt;
[7aeb52cb]488 free((char *) entry->name);
[61784ed]489 free(entry);
490}
491
[0e80e40]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;
[fa792e8]517 vfs_stat_t finfo;
[4fcc2de]518 char newdir[256];
519 char *ndir = NULL;
[7aeb52cb]520 panel_entry_attr_t attr;
[0e80e40]521 errno_t rc;
522
[4fcc2de]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 */
[7aeb52cb]543 panel_entry_attr_init(&attr);
544 attr.name = "..";
545 attr.isdir = true;
546
547 rc = panel_entry_append(panel, &attr);
[4fcc2de]548 if (rc != EOK)
549 goto error;
550 }
[0e80e40]551
552 dirent = readdir(dir);
553 while (dirent != NULL) {
[fa792e8]554 rc = vfs_stat_path(dirent->d_name, &finfo);
[4fcc2de]555 if (rc != EOK) {
556 /* Possibly a stale entry */
557 dirent = readdir(dir);
558 continue;
559 }
[fa792e8]560
[7aeb52cb]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);
[0e80e40]568 if (rc != EOK)
569 goto error;
[fa792e8]570
[0e80e40]571 dirent = readdir(dir);
572 }
573
574 closedir(dir);
575
[1eb0fafe]576 rc = panel_sort(panel);
577 if (rc != EOK)
578 goto error;
579
[0e80e40]580 panel->cursor = panel_first(panel);
[be1d74c1]581 panel->cursor_idx = 0;
[0e80e40]582 panel->page = panel_first(panel);
[be1d74c1]583 panel->page_idx = 0;
[4fcc2de]584 free(panel->dir);
585 panel->dir = ndir;
[0e80e40]586 return EOK;
587error:
[4fcc2de]588 (void) vfs_cwd_set(panel->dir);
589 if (ndir != NULL)
590 free(ndir);
591 if (dir != NULL)
592 closedir(dir);
[0e80e40]593 return rc;
594}
595
[1eb0fafe]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;
[fa792e8]650 int dcmp;
651
652 /* Sort directories first */
653 dcmp = b->isdir - a->isdir;
654 if (dcmp != 0)
655 return dcmp;
[1eb0fafe]656
657 return str_cmp(a->name, b->name);
658}
659
[61784ed]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
[be1d74c1]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
[61784ed]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}
[b36ebb42]707
[be1d74c1]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
[8c72f533]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 */
[be1d74c1]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
[8c72f533]739 rows = panel_page_size(panel);
[be1d74c1]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
[8c72f533]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
[4fcc2de]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)
[01e9991]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)
[4fcc2de]974{
975 gfx_context_t *gc = ui_window_get_gc(panel->window);
976 errno_t rc;
977
[01e9991]978 assert(entry->isdir);
[4fcc2de]979
980 panel_clear_entries(panel);
981
[01e9991]982 rc = panel_read_dir(panel, entry->name);
983 if (rc != EOK)
[4fcc2de]984 return rc;
985
986 rc = panel_paint(panel);
[01e9991]987 if (rc != EOK)
[4fcc2de]988 return rc;
989
990 return gfx_update(gc);
991}
992
[01e9991]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
[6aa85c1]1027/** @}
1028 */
Note: See TracBrowser for help on using the repository browser.