From 0ce287503cd7921c242946c10b8b031ed9431b53 Mon Sep 17 00:00:00 2001 From: Aidan MacDonald Date: Thu, 10 Mar 2022 14:17:20 +0000 Subject: x1000: bootloader: use list widget for the recovery menu This allows the menu to scroll when there isn't enough vertical space to display the whole menu. Change-Id: I6dc3e84cde0c1b003e579f107ae7f13e0ea33a5a --- bootloader/x1000/recovery.c | 125 +++++++++++++++++++++++++++----------------- 1 file changed, 78 insertions(+), 47 deletions(-) (limited to 'bootloader/x1000/recovery.c') diff --git a/bootloader/x1000/recovery.c b/bootloader/x1000/recovery.c index 4d806b26a4..3d6a079af8 100644 --- a/bootloader/x1000/recovery.c +++ b/bootloader/x1000/recovery.c @@ -50,77 +50,108 @@ static const struct menuitem recovery_items[] = { {MENUITEM_ACTION, "Restore", &bootloader_restore}, }; -static void put_help_line(int line, const char* str1, const char* str2) +static void recmenu_draw_item(const struct bl_listitem* item) { - int width = LCD_WIDTH / SYSFONT_WIDTH; - lcd_puts(0, line, str1); - lcd_puts(width - strlen(str2), line, str2); + const struct menuitem* mu = &recovery_items[item->index]; + const char* fmt; + + switch(mu->type) { + case MENUITEM_HEADING: + fmt = "[%s]"; + break; + + case MENUITEM_ACTION: + default: + if(item->index == item->list->selected_item) + fmt = "=> %s"; + else + fmt = " %s"; + break; + } + + lcd_putsxyf(item->x, item->y, fmt, mu->text); } -void recovery_menu(void) +static void recmenu_scroll(struct bl_list* list, int dir) { - const int n_items = sizeof(recovery_items)/sizeof(struct menuitem); + int start, end, step; + + if(dir < 0) { + start = list->selected_item - 1; + end = -1; + step = -1; + } else if(dir > 0) { + start = list->selected_item + 1; + end = list->num_items; + step = 1; + } else { + return; + } - int selection = 0; - while(recovery_items[selection].type != MENUITEM_ACTION) - ++selection; + for(int i = start; i != end; i += step) { + if(recovery_items[i].action) { + gui_list_select(list, i); - while(1) { - clearscreen(); - putcenter_y(0, "Rockbox recovery menu"); - - int top_line = 2; + /* always show one item above the selection to ensure + * the topmost heading is visible */ + if(list->selected_item == list->top_item && list->top_item > 0) + list->top_item--; - /* draw the menu */ - for(int i = 0; i < n_items; ++i) { - switch(recovery_items[i].type) { - case MENUITEM_HEADING: - lcd_putsf(0, top_line+i, "[%s]", recovery_items[i].text); - break; + break; + } + } +} - case MENUITEM_ACTION: - lcd_puts(3, top_line+i, recovery_items[i].text); - break; +static void put_help_line(int y, int line, const char* str1, const char* str2) +{ + y += line*SYSFONT_HEIGHT; + lcd_putsxy(0, y, str1); + lcd_putsxy(LCD_WIDTH - strlen(str2)*SYSFONT_WIDTH, y, str2); +} - default: - break; - } - } +void recovery_menu(void) +{ + struct viewport vp = { + .x = 0, .y = SYSFONT_HEIGHT, + .width = LCD_WIDTH, + .height = LCD_HEIGHT - SYSFONT_HEIGHT*5, + }; + lcd_init_viewport(&vp); + + struct bl_list list; + gui_list_init(&list, &vp); + list.num_items = ARRAYLEN(recovery_items); + list.selected_item = 1; /* first item is a heading */ + list.draw_item = recmenu_draw_item; - /* draw the selection marker */ - lcd_puts(0, top_line+selection, "=>"); + while(1) { + clearscreen(); + putcenter_y(0, "Rockbox recovery menu"); /* draw the help text */ - int line = (LCD_HEIGHT - SYSFONT_HEIGHT)/SYSFONT_HEIGHT - 3; - put_help_line(line++, BL_DOWN_NAME "/" BL_UP_NAME, "move cursor"); - put_help_line(line++, BL_SELECT_NAME, "select item"); - put_help_line(line++, BL_QUIT_NAME, "power off"); + int ypos = LCD_HEIGHT - 4*SYSFONT_HEIGHT; + put_help_line(ypos, 0, BL_DOWN_NAME "/" BL_UP_NAME, "move cursor"); + put_help_line(ypos, 1, BL_SELECT_NAME, "select item"); + put_help_line(ypos, 2, BL_QUIT_NAME, "power off"); + + /* draw the list */ + gui_list_draw(&list); lcd_update(); /* handle input */ switch(get_button(TIMEOUT_BLOCK)) { case BL_SELECT: { - if(recovery_items[selection].action) - recovery_items[selection].action(); + if(recovery_items[list.selected_item].action) + recovery_items[list.selected_item].action(); } break; case BL_UP: - for(int i = selection-1; i >= 0; --i) { - if(recovery_items[i].action) { - selection = i; - break; - } - } + recmenu_scroll(&list, -1); break; case BL_DOWN: - for(int i = selection+1; i < n_items; ++i) { - if(recovery_items[i].action) { - selection = i; - break; - } - } + recmenu_scroll(&list, 1); break; case BL_QUIT: -- cgit v1.2.3