source: mainline/uspace/app/nav/panel.c@ 9bed565

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

Highlight directories and sort them first

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