Index: uspace/app/nav/panel.c
===================================================================
--- uspace/app/nav/panel.c	(revision 9f7e9bbd7d961604b52e02c0ee7c4dd0f3c4f46f)
+++ uspace/app/nav/panel.c	(revision be1d74c1177b171bc7d692a94141566e1359937f)
@@ -49,4 +49,5 @@
 static void panel_ctl_destroy(void *);
 static errno_t panel_ctl_paint(void *);
+static ui_evclaim_t panel_ctl_kbd_event(void *, kbd_event_t *);
 static ui_evclaim_t panel_ctl_pos_event(void *, pos_event_t *);
 
@@ -55,4 +56,5 @@
 	.destroy = panel_ctl_destroy,
 	.paint = panel_ctl_paint,
+	.kbd_event = panel_ctl_kbd_event,
 	.pos_event = panel_ctl_pos_event
 };
@@ -90,4 +92,5 @@
 	panel->window = window;
 	list_initialize(&panel->entries);
+	panel->entries_cnt = 0;
 	*rpanel = panel;
 	return EOK;
@@ -115,17 +118,70 @@
 }
 
-/** Paint panel.
- *
- * @param panel Panel
- */
-errno_t panel_paint(panel_t *panel)
-{
+/** Paint panel entry.
+ *
+ * @param entry Panel entry
+ * @param entry_idx Entry index (within list of entries)
+ * @return EOK on success or an error code
+ */
+errno_t panel_entry_paint(panel_entry_t *entry, size_t entry_idx)
+{
+	panel_t *panel = entry->panel;
 	gfx_context_t *gc = ui_window_get_gc(panel->window);
 	ui_resource_t *res = ui_window_get_res(panel->window);
 	gfx_font_t *font = ui_resource_get_font(res);
 	gfx_text_fmt_t fmt;
-	panel_entry_t *entry;
 	gfx_coord2_t pos;
 	gfx_rect_t rect;
+	size_t rows;
+	errno_t rc;
+
+	gfx_text_fmt_init(&fmt);
+
+	rows = panel->rect.p1.y - panel->rect.p0.y - 2;
+
+	/* Do not display entry outside of current page */
+	if (entry_idx < panel->page_idx ||
+	    entry_idx >= panel->page_idx + rows)
+		return EOK;
+
+	pos.x = panel->rect.p0.x + 1;
+	pos.y = panel->rect.p0.y + 1 + entry_idx - panel->page_idx;
+
+	if (entry == panel->cursor)
+		fmt.color = panel->curs_color;
+	else
+		fmt.color = panel->color;
+
+	/* Draw entry background */
+	rect.p0 = pos;
+	rect.p1.x = panel->rect.p1.x - 1;
+	rect.p1.y = rect.p0.y + 1;
+
+	rc = gfx_set_color(gc, fmt.color);
+	if (rc != EOK)
+		return rc;
+
+	rc = gfx_fill_rect(gc, &rect);
+	if (rc != EOK)
+		return rc;
+
+	rc = gfx_puttext(font, &pos, &fmt, entry->name);
+	if (rc != EOK)
+		return rc;
+
+	return EOK;
+}
+
+/** Paint panel.
+ *
+ * @param panel Panel
+ */
+errno_t panel_paint(panel_t *panel)
+{
+	gfx_context_t *gc = ui_window_get_gc(panel->window);
+	ui_resource_t *res = ui_window_get_res(panel->window);
+	gfx_text_fmt_t fmt;
+	panel_entry_t *entry;
+	int i, lines;
 	errno_t rc;
 
@@ -145,33 +201,14 @@
 		return rc;
 
-	pos.x = panel->rect.p0.x + 1;
-	pos.y = panel->rect.p0.y + 1;
+	lines = panel->rect.p1.y - panel->rect.p0.y - 2;
+	i = 0;
 
 	entry = panel->page;
-	while (entry != NULL && pos.y < panel->rect.p1.y - 1) {
-		if (entry == panel->cursor) {
-			/* Draw cursor background */
-			rect.p0 = pos;
-			rect.p1.x = panel->rect.p1.x - 1;
-			rect.p1.y = rect.p0.y + 1;
-
-			rc = gfx_set_color(gc, panel->curs_color);
-			if (rc != EOK)
-				return rc;
-
-			rc = gfx_fill_rect(gc, &rect);
-			if (rc != EOK)
-				return rc;
-
-			fmt.color = panel->curs_color;
-		} else {
-			fmt.color = panel->color;
-		}
-
-		rc = gfx_puttext(font, &pos, &fmt, entry->name);
+	while (entry != NULL && i < lines) {
+		rc = panel_entry_paint(entry, panel->page_idx + i);
 		if (rc != EOK)
 			return rc;
 
-		pos.y++;
+		++i;
 		entry = panel_next(entry);
 	}
@@ -184,4 +221,36 @@
 }
 
+/** Handle panel keyboard event.
+ *
+ * @param panel Panel
+ * @param event Keyboard event
+ * @return ui_claimed iff event was claimed
+ */
+ui_evclaim_t panel_kbd_event(panel_t *panel, kbd_event_t *event)
+{
+	if (event->type == KEY_PRESS) {
+		if ((event->mods & (KM_CTRL | KM_ALT | KM_SHIFT)) == 0) {
+			switch (event->key) {
+			case KC_UP:
+				panel_cursor_up(panel);
+				break;
+			case KC_DOWN:
+				panel_cursor_down(panel);
+				break;
+			case KC_HOME:
+				panel_cursor_top(panel);
+				break;
+			case KC_END:
+				panel_cursor_bottom(panel);
+				break;
+			default:
+				break;
+			}
+		}
+	}
+
+	return ui_unclaimed;
+}
+
 /** Handle panel position event.
  *
@@ -236,4 +305,17 @@
 
 	return panel_paint(panel);
+}
+
+/** Handle panel control keyboard event.
+ *
+ * @param arg Argument (panel_t *)
+ * @param kbd_event Keyboard event
+ * @return @c ui_claimed iff the event is claimed
+ */
+ui_evclaim_t panel_ctl_kbd_event(void *arg, kbd_event_t *event)
+{
+	panel_t *panel = (panel_t *) arg;
+
+	return panel_kbd_event(panel, event);
 }
 
@@ -276,4 +358,5 @@
 	link_initialize(&entry->lentries);
 	list_append(&entry->lentries, &panel->entries);
+	++panel->entries_cnt;
 	return EOK;
 }
@@ -291,4 +374,5 @@
 
 	list_remove(&entry->lentries);
+	--entry->panel->entries_cnt;
 	free(entry->name);
 	free(entry);
@@ -337,5 +421,7 @@
 
 	panel->cursor = panel_first(panel);
+	panel->cursor_idx = 0;
 	panel->page = panel_first(panel);
+	panel->page_idx = 0;
 	return EOK;
 error:
@@ -360,4 +446,20 @@
 }
 
+/** Return last panel entry.
+ *
+ * @panel Panel
+ * @return Last panel entry or @c NULL if there are no entries
+ */
+panel_entry_t *panel_last(panel_t *panel)
+{
+	link_t *link;
+
+	link = list_last(&panel->entries);
+	if (link == NULL)
+		return NULL;
+
+	return list_get_instance(link, panel_entry_t, lentries);
+}
+
 /** Return next panel entry.
  *
@@ -376,4 +478,130 @@
 }
 
+/** Return previous panel entry.
+ *
+ * @param cur Current entry
+ * @return Previous entry or @c NULL if @a cur is the first entry
+ */
+panel_entry_t *panel_prev(panel_entry_t *cur)
+{
+	link_t *link;
+
+	link = list_prev(&cur->lentries, &cur->panel->entries);
+	if (link == NULL)
+		return NULL;
+
+	return list_get_instance(link, panel_entry_t, lentries);
+}
+
+void panel_cursor_move(panel_t *panel, panel_entry_t *entry, size_t entry_idx)
+{
+	gfx_context_t *gc = ui_window_get_gc(panel->window);
+	panel_entry_t *old_cursor;
+	size_t old_idx;
+	size_t rows;
+	panel_entry_t *e;
+	size_t i;
+
+	rows = panel->rect.p1.y - panel->rect.p0.y - 2;
+
+	old_cursor = panel->cursor;
+	old_idx = panel->cursor_idx;
+
+	panel->cursor = entry;
+	panel->cursor_idx = entry_idx;
+
+	if (entry_idx >= panel->page_idx &&
+	    entry_idx < panel->page_idx + rows) {
+		/*
+		 * If cursor is still on the current page, we're not
+		 * scrolling. Just unpaint old cursor and paint new
+		 * cursor.
+		 */
+		panel_entry_paint(old_cursor, old_idx);
+		panel_entry_paint(panel->cursor, panel->cursor_idx);
+
+		(void) gfx_update(gc);
+	} else {
+		/*
+		 * Need to scroll and update all rows.
+		 */
+
+		/* Scrolling up */
+		if (entry_idx < panel->page_idx) {
+			panel->page = entry;
+			panel->page_idx = entry_idx;
+		}
+
+		/* Scrolling down */
+		if (entry_idx >= panel->page_idx + rows) {
+			if (entry_idx >= rows) {
+				panel->page_idx = entry_idx - rows + 1;
+				/* Find first page entry (go back rows - 1) */
+				e = entry;
+				for (i = 0; i < rows - 1; i++) {
+					e = panel_prev(e);
+				}
+
+				/* Should be valid */
+				assert(e != NULL);
+				panel->page = e;
+			} else {
+				panel->page = panel_first(panel);
+				panel->page_idx = 0;
+			}
+		}
+
+		(void) panel_paint(panel);
+	}
+}
+
+/** Move cursor one entry up.
+ *
+ * @param panel Panel
+ */
+void panel_cursor_up(panel_t *panel)
+{
+	panel_entry_t *prev;
+	size_t prev_idx;
+
+	prev = panel_prev(panel->cursor);
+	prev_idx = panel->cursor_idx - 1;
+	if (prev != NULL)
+		panel_cursor_move(panel, prev, prev_idx);
+}
+
+/** Move cursor one entry down.
+ *
+ * @param panel Panel
+ */
+void panel_cursor_down(panel_t *panel)
+{
+	panel_entry_t *next;
+	size_t next_idx;
+
+	next = panel_next(panel->cursor);
+	next_idx = panel->cursor_idx + 1;
+	if (next != NULL)
+		panel_cursor_move(panel, next, next_idx);
+}
+
+/** Move cursor to top.
+ *
+ * @param panel Panel
+ */
+void panel_cursor_top(panel_t *panel)
+{
+	panel_cursor_move(panel, panel_first(panel), 0);
+}
+
+/** Move cursor to bottom.
+ *
+ * @param panel Panel
+ */
+void panel_cursor_bottom(panel_t *panel)
+{
+	panel_cursor_move(panel, panel_last(panel), panel->entries_cnt - 1);
+}
+
 /** @}
  */
Index: uspace/app/nav/panel.h
===================================================================
--- uspace/app/nav/panel.h	(revision 9f7e9bbd7d961604b52e02c0ee7c4dd0f3c4f46f)
+++ uspace/app/nav/panel.h	(revision be1d74c1177b171bc7d692a94141566e1359937f)
@@ -41,4 +41,5 @@
 #include <gfx/color.h>
 #include <gfx/coord.h>
+#include <io/kbd_event.h>
 #include <io/pos_event.h>
 #include <ui/control.h>
@@ -83,14 +84,25 @@
 	list_t entries;
 
+	/** Number of entries */
+	size_t entries_cnt;
+
 	/** First entry of current page */
 	panel_entry_t *page;
 
+	/** Index of first entry of current page */
+	size_t page_idx;
+
 	/** Cursor position */
 	panel_entry_t *cursor;
+
+	/** Index of entry under cursor */
+	size_t cursor_idx;
 } panel_t;
 
 extern errno_t panel_create(ui_window_t *, panel_t **);
 extern void panel_destroy(panel_t *);
+extern errno_t panel_entry_paint(panel_entry_t *, size_t);
 extern errno_t panel_paint(panel_t *);
+extern ui_evclaim_t panel_kbd_event(panel_t *, kbd_event_t *);
 extern ui_evclaim_t panel_pos_event(panel_t *, pos_event_t *);
 extern ui_control_t *panel_ctl(panel_t *);
@@ -101,5 +113,12 @@
 extern errno_t panel_read_dir(panel_t *, const char *);
 extern panel_entry_t *panel_first(panel_t *);
+extern panel_entry_t *panel_last(panel_t *);
 extern panel_entry_t *panel_next(panel_entry_t *);
+extern panel_entry_t *panel_prev(panel_entry_t *);
+extern void panel_cursor_move(panel_t *, panel_entry_t *, size_t);
+extern void panel_cursor_up(panel_t *);
+extern void panel_cursor_down(panel_t *);
+extern void panel_cursor_top(panel_t *);
+extern void panel_cursor_bottom(panel_t *);
 
 #endif
Index: uspace/app/nav/test/panel.c
===================================================================
--- uspace/app/nav/test/panel.c	(revision 9f7e9bbd7d961604b52e02c0ee7c4dd0f3c4f46f)
+++ uspace/app/nav/test/panel.c	(revision be1d74c1177b171bc7d692a94141566e1359937f)
@@ -28,4 +28,6 @@
 
 #include <errno.h>
+#include <io/kbd_event.h>
+#include <io/pos_event.h>
 #include <pcut/pcut.h>
 #include <stdio.h>
@@ -49,6 +51,6 @@
 }
 
-/** Test panel_paint() */
-PCUT_TEST(paint)
+/** Test panel_entry_paint() */
+PCUT_TEST(entry_paint)
 {
 	ui_t *ui;
@@ -70,5 +72,8 @@
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
-	rc = panel_paint(panel);
+	rc = panel_entry_append(panel, "a", 1);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = panel_entry_paint(panel_first(panel), 0);
 	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
 
@@ -78,4 +83,33 @@
 }
 
+/** Test panel_paint() */
+PCUT_TEST(paint)
+{
+	ui_t *ui;
+	ui_window_t *window;
+	ui_wnd_params_t params;
+	panel_t *panel;
+	errno_t rc;
+
+	rc = ui_create_disp(NULL, &ui);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	ui_wnd_params_init(&params);
+	params.caption = "Test";
+
+	rc = ui_window_create(ui, &params, &window);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = panel_create(window, &panel);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = panel_paint(panel);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	panel_destroy(panel);
+	ui_window_destroy(window);
+	ui_destroy(ui);
+}
+
 /** panel_ctl() returns a valid UI control */
 PCUT_TEST(ctl)
@@ -90,4 +124,30 @@
 	control = panel_ctl(panel);
 	PCUT_ASSERT_NOT_NULL(control);
+
+	panel_destroy(panel);
+}
+
+/** Test panel_kbd_event() */
+PCUT_TEST(kbd_event)
+{
+	panel_t *panel;
+	ui_control_t *control;
+	ui_evclaim_t claimed;
+	kbd_event_t event;
+	errno_t rc;
+
+	rc = panel_create(NULL, &panel);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	control = panel_ctl(panel);
+	PCUT_ASSERT_NOT_NULL(control);
+
+	event.type = KEY_PRESS;
+	event.key = KC_ENTER;
+	event.mods = 0;
+	event.c = '\0';
+
+	claimed = panel_kbd_event(panel, &event);
+	PCUT_ASSERT_EQUALS(ui_unclaimed, claimed);
 
 	panel_destroy(panel);
@@ -108,4 +168,10 @@
 	control = panel_ctl(panel);
 	PCUT_ASSERT_NOT_NULL(control);
+
+	event.pos_id = 0;
+	event.type = POS_PRESS;
+	event.btn_num = 1;
+	event.hpos = 0;
+	event.vpos = 0;
 
 	claimed = panel_pos_event(panel, &event);
@@ -310,4 +376,40 @@
 }
 
+/** panel_last() returns valid entry or @c NULL as appropriate */
+PCUT_TEST(last)
+{
+	panel_t *panel;
+	panel_entry_t *entry;
+	errno_t rc;
+
+	rc = panel_create(NULL, &panel);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	entry = panel_last(panel);
+	PCUT_ASSERT_NULL(entry);
+
+	/* Add one entry */
+	rc = panel_entry_append(panel, "a", 1);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* Now try getting it */
+	entry = panel_last(panel);
+	PCUT_ASSERT_NOT_NULL(entry);
+	PCUT_ASSERT_STR_EQUALS("a", entry->name);
+	PCUT_ASSERT_INT_EQUALS(1, entry->size);
+
+	/* Add another entry */
+	rc = panel_entry_append(panel, "b", 2);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* We should get new entry now */
+	entry = panel_last(panel);
+	PCUT_ASSERT_NOT_NULL(entry);
+	PCUT_ASSERT_STR_EQUALS("b", entry->name);
+	PCUT_ASSERT_INT_EQUALS(2, entry->size);
+
+	panel_destroy(panel);
+}
+
 /** panel_next() returns the next entry or @c NULL as appropriate */
 PCUT_TEST(next)
@@ -347,3 +449,324 @@
 }
 
+/** panel_prev() returns the previous entry or @c NULL as appropriate */
+PCUT_TEST(prev)
+{
+	panel_t *panel;
+	panel_entry_t *entry;
+	errno_t rc;
+
+	rc = panel_create(NULL, &panel);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* Add one entry */
+	rc = panel_entry_append(panel, "a", 1);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* Now try getting its predecessor */
+	entry = panel_last(panel);
+	PCUT_ASSERT_NOT_NULL(entry);
+
+	entry = panel_prev(entry);
+	PCUT_ASSERT_NULL(entry);
+
+	/* Add another entry */
+	rc = panel_entry_append(panel, "b", 2);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* Try getting the predecessor of the new entry */
+	entry = panel_last(panel);
+	PCUT_ASSERT_NOT_NULL(entry);
+
+	entry = panel_prev(entry);
+	PCUT_ASSERT_NOT_NULL(entry);
+	PCUT_ASSERT_STR_EQUALS("a", entry->name);
+	PCUT_ASSERT_INT_EQUALS(1, entry->size);
+
+	panel_destroy(panel);
+}
+
+/** panel_cursor_move() ... */
+PCUT_TEST(cursor_move)
+{
+}
+
+/** panel_cursor_up() moves cursor one entry up */
+PCUT_TEST(cursor_up)
+{
+	ui_t *ui;
+	ui_window_t *window;
+	ui_wnd_params_t params;
+	panel_t *panel;
+	gfx_rect_t rect;
+	errno_t rc;
+
+	rc = ui_create_disp(NULL, &ui);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	ui_wnd_params_init(&params);
+	params.caption = "Test";
+
+	rc = ui_window_create(ui, &params, &window);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = panel_create(window, &panel);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rect.p0.x = 0;
+	rect.p0.y = 0;
+	rect.p1.x = 10;
+	rect.p1.y = 4; // XXX Assuming this makes page size 2
+	panel_set_rect(panel, &rect);
+
+	/* Add tree entries (more than page size, which is 2) */
+	rc = panel_entry_append(panel, "a", 1);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = panel_entry_append(panel, "b", 2);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = panel_entry_append(panel, "c", 3);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* Cursor to the last entry and page start to the next-to-last entry */
+	panel->cursor = panel_last(panel);
+	panel->cursor_idx = 2;
+	panel->page = panel_prev(panel->cursor);
+	panel->page_idx = 1;
+
+	/* Move cursor one entry up */
+	panel_cursor_up(panel);
+
+	/* Cursor and page start should now both be at the second entry */
+	PCUT_ASSERT_STR_EQUALS("b", panel->cursor->name);
+	PCUT_ASSERT_INT_EQUALS(2, panel->cursor->size);
+	PCUT_ASSERT_INT_EQUALS(1, panel->cursor_idx);
+	PCUT_ASSERT_EQUALS(panel->cursor, panel->page);
+	PCUT_ASSERT_INT_EQUALS(1, panel->page_idx);
+
+	/* Move cursor one entry up. This should scroll up. */
+	panel_cursor_up(panel);
+
+	/* Cursor and page start should now both be at the first entry */
+	PCUT_ASSERT_STR_EQUALS("a", panel->cursor->name);
+	PCUT_ASSERT_INT_EQUALS(1, panel->cursor->size);
+	PCUT_ASSERT_INT_EQUALS(0, panel->cursor_idx);
+	PCUT_ASSERT_EQUALS(panel->cursor, panel->page);
+	PCUT_ASSERT_INT_EQUALS(0, panel->page_idx);
+
+	/* Moving further up should do nothing (we are at the top). */
+	panel_cursor_up(panel);
+
+	/* Cursor and page start should still be at the first entry */
+	PCUT_ASSERT_STR_EQUALS("a", panel->cursor->name);
+	PCUT_ASSERT_INT_EQUALS(1, panel->cursor->size);
+	PCUT_ASSERT_INT_EQUALS(0, panel->cursor_idx);
+	PCUT_ASSERT_EQUALS(panel->cursor, panel->page);
+	PCUT_ASSERT_INT_EQUALS(0, panel->page_idx);
+
+	panel_destroy(panel);
+	ui_window_destroy(window);
+	ui_destroy(ui);
+}
+
+/** panel_cursor_down() moves cursor one entry down */
+PCUT_TEST(cursor_down)
+{
+	ui_t *ui;
+	ui_window_t *window;
+	ui_wnd_params_t params;
+	panel_t *panel;
+	gfx_rect_t rect;
+	errno_t rc;
+
+	rc = ui_create_disp(NULL, &ui);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	ui_wnd_params_init(&params);
+	params.caption = "Test";
+
+	rc = ui_window_create(ui, &params, &window);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = panel_create(window, &panel);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rect.p0.x = 0;
+	rect.p0.y = 0;
+	rect.p1.x = 10;
+	rect.p1.y = 4; // XXX Assuming this makes page size 2
+	panel_set_rect(panel, &rect);
+
+	/* Add tree entries (more than page size, which is 2) */
+	rc = panel_entry_append(panel, "a", 1);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = panel_entry_append(panel, "b", 2);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = panel_entry_append(panel, "c", 3);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* Cursor and page start to the first entry */
+	panel->cursor = panel_first(panel);
+	panel->cursor_idx = 0;
+	panel->page = panel->cursor;
+	panel->page_idx = 0;
+
+	/* Move cursor one entry down */
+	panel_cursor_down(panel);
+
+	/* Cursor should now be at the second entry, page stays the same */
+	PCUT_ASSERT_STR_EQUALS("b", panel->cursor->name);
+	PCUT_ASSERT_INT_EQUALS(2, panel->cursor->size);
+	PCUT_ASSERT_INT_EQUALS(1, panel->cursor_idx);
+	PCUT_ASSERT_EQUALS(panel_first(panel), panel->page);
+	PCUT_ASSERT_INT_EQUALS(0, panel->page_idx);
+
+	/* Move cursor one entry down. This should scroll down. */
+	panel_cursor_down(panel);
+
+	/* Cursor should now be at the third and page at the second entry. */
+	PCUT_ASSERT_STR_EQUALS("c", panel->cursor->name);
+	PCUT_ASSERT_INT_EQUALS(3, panel->cursor->size);
+	PCUT_ASSERT_INT_EQUALS(2, panel->cursor_idx);
+	PCUT_ASSERT_STR_EQUALS("b", panel->page->name);
+	PCUT_ASSERT_INT_EQUALS(2, panel->page->size);
+	PCUT_ASSERT_INT_EQUALS(1, panel->page_idx);
+
+	/* Moving further down should do nothing (we are at the bottom). */
+	panel_cursor_down(panel);
+
+	/* Cursor should still be at the third and page at the second entry. */
+	PCUT_ASSERT_STR_EQUALS("c", panel->cursor->name);
+	PCUT_ASSERT_INT_EQUALS(3, panel->cursor->size);
+	PCUT_ASSERT_INT_EQUALS(2, panel->cursor_idx);
+	PCUT_ASSERT_STR_EQUALS("b", panel->page->name);
+	PCUT_ASSERT_INT_EQUALS(2, panel->page->size);
+	PCUT_ASSERT_INT_EQUALS(1, panel->page_idx);
+
+	panel_destroy(panel);
+	ui_window_destroy(window);
+	ui_destroy(ui);
+}
+
+/** panel_cursor_top() moves cursor to the first entry */
+PCUT_TEST(cursor_top)
+{
+	ui_t *ui;
+	ui_window_t *window;
+	ui_wnd_params_t params;
+	panel_t *panel;
+	gfx_rect_t rect;
+	errno_t rc;
+
+	rc = ui_create_disp(NULL, &ui);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	ui_wnd_params_init(&params);
+	params.caption = "Test";
+
+	rc = ui_window_create(ui, &params, &window);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = panel_create(window, &panel);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rect.p0.x = 0;
+	rect.p0.y = 0;
+	rect.p1.x = 10;
+	rect.p1.y = 4; // XXX Assuming this makes page size 2
+	panel_set_rect(panel, &rect);
+
+	/* Add tree entries (more than page size, which is 2) */
+	rc = panel_entry_append(panel, "a", 1);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = panel_entry_append(panel, "b", 2);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = panel_entry_append(panel, "c", 3);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* Cursor to the last entry and page start to the next-to-last entry */
+	panel->cursor = panel_last(panel);
+	panel->cursor_idx = 2;
+	panel->page = panel_prev(panel->cursor);
+	panel->page_idx = 1;
+
+	/* Move cursor to the top. This should scroll up. */
+	panel_cursor_top(panel);
+
+	/* Cursor and page start should now both be at the first entry */
+	PCUT_ASSERT_STR_EQUALS("a", panel->cursor->name);
+	PCUT_ASSERT_INT_EQUALS(1, panel->cursor->size);
+	PCUT_ASSERT_INT_EQUALS(0, panel->cursor_idx);
+	PCUT_ASSERT_EQUALS(panel->cursor, panel->page);
+	PCUT_ASSERT_INT_EQUALS(0, panel->page_idx);
+
+	panel_destroy(panel);
+	ui_window_destroy(window);
+	ui_destroy(ui);
+}
+
+/** panel_cursor_bottom() moves cursor to the last entry */
+PCUT_TEST(cursor_bottom)
+{
+	ui_t *ui;
+	ui_window_t *window;
+	ui_wnd_params_t params;
+	panel_t *panel;
+	gfx_rect_t rect;
+	errno_t rc;
+
+	rc = ui_create_disp(NULL, &ui);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	ui_wnd_params_init(&params);
+	params.caption = "Test";
+
+	rc = ui_window_create(ui, &params, &window);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = panel_create(window, &panel);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rect.p0.x = 0;
+	rect.p0.y = 0;
+	rect.p1.x = 10;
+	rect.p1.y = 4; // XXX Assuming this makes page size 2
+	panel_set_rect(panel, &rect);
+
+	/* Add tree entries (more than page size, which is 2) */
+	rc = panel_entry_append(panel, "a", 1);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = panel_entry_append(panel, "b", 2);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	rc = panel_entry_append(panel, "c", 3);
+	PCUT_ASSERT_ERRNO_VAL(EOK, rc);
+
+	/* Cursor and page start to the first entry */
+	panel->cursor = panel_first(panel);
+	panel->cursor_idx = 0;
+	panel->page = panel->cursor;
+	panel->page_idx = 0;
+
+	/* Move cursor to the bottom. This should scroll down. */
+	panel_cursor_bottom(panel);
+
+	/* Cursor should now be at the third and page at the second entry. */
+	PCUT_ASSERT_STR_EQUALS("c", panel->cursor->name);
+	PCUT_ASSERT_INT_EQUALS(3, panel->cursor->size);
+	PCUT_ASSERT_INT_EQUALS(2, panel->cursor_idx);
+	PCUT_ASSERT_STR_EQUALS("b", panel->page->name);
+	PCUT_ASSERT_INT_EQUALS(2, panel->page->size);
+	PCUT_ASSERT_INT_EQUALS(1, panel->page_idx);
+
+	panel_destroy(panel);
+	ui_window_destroy(window);
+	ui_destroy(ui);
+}
+
 PCUT_EXPORT(panel);
