diff options
-rw-r--r-- | bootloader/x1000/recovery.c | 125 |
1 files changed, 78 insertions, 47 deletions
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[] = { | |||
50 | {MENUITEM_ACTION, "Restore", &bootloader_restore}, | 50 | {MENUITEM_ACTION, "Restore", &bootloader_restore}, |
51 | }; | 51 | }; |
52 | 52 | ||
53 | static void put_help_line(int line, const char* str1, const char* str2) | 53 | static void recmenu_draw_item(const struct bl_listitem* item) |
54 | { | 54 | { |
55 | int width = LCD_WIDTH / SYSFONT_WIDTH; | 55 | const struct menuitem* mu = &recovery_items[item->index]; |
56 | lcd_puts(0, line, str1); | 56 | const char* fmt; |
57 | lcd_puts(width - strlen(str2), line, str2); | 57 | |
58 | switch(mu->type) { | ||
59 | case MENUITEM_HEADING: | ||
60 | fmt = "[%s]"; | ||
61 | break; | ||
62 | |||
63 | case MENUITEM_ACTION: | ||
64 | default: | ||
65 | if(item->index == item->list->selected_item) | ||
66 | fmt = "=> %s"; | ||
67 | else | ||
68 | fmt = " %s"; | ||
69 | break; | ||
70 | } | ||
71 | |||
72 | lcd_putsxyf(item->x, item->y, fmt, mu->text); | ||
58 | } | 73 | } |
59 | 74 | ||
60 | void recovery_menu(void) | 75 | static void recmenu_scroll(struct bl_list* list, int dir) |
61 | { | 76 | { |
62 | const int n_items = sizeof(recovery_items)/sizeof(struct menuitem); | 77 | int start, end, step; |
78 | |||
79 | if(dir < 0) { | ||
80 | start = list->selected_item - 1; | ||
81 | end = -1; | ||
82 | step = -1; | ||
83 | } else if(dir > 0) { | ||
84 | start = list->selected_item + 1; | ||
85 | end = list->num_items; | ||
86 | step = 1; | ||
87 | } else { | ||
88 | return; | ||
89 | } | ||
63 | 90 | ||
64 | int selection = 0; | 91 | for(int i = start; i != end; i += step) { |
65 | while(recovery_items[selection].type != MENUITEM_ACTION) | 92 | if(recovery_items[i].action) { |
66 | ++selection; | 93 | gui_list_select(list, i); |
67 | 94 | ||
68 | while(1) { | 95 | /* always show one item above the selection to ensure |
69 | clearscreen(); | 96 | * the topmost heading is visible */ |
70 | putcenter_y(0, "Rockbox recovery menu"); | 97 | if(list->selected_item == list->top_item && list->top_item > 0) |
71 | 98 | list->top_item--; | |
72 | int top_line = 2; | ||
73 | 99 | ||
74 | /* draw the menu */ | 100 | break; |
75 | for(int i = 0; i < n_items; ++i) { | 101 | } |
76 | switch(recovery_items[i].type) { | 102 | } |
77 | case MENUITEM_HEADING: | 103 | } |
78 | lcd_putsf(0, top_line+i, "[%s]", recovery_items[i].text); | ||
79 | break; | ||
80 | 104 | ||
81 | case MENUITEM_ACTION: | 105 | static void put_help_line(int y, int line, const char* str1, const char* str2) |
82 | lcd_puts(3, top_line+i, recovery_items[i].text); | 106 | { |
83 | break; | 107 | y += line*SYSFONT_HEIGHT; |
108 | lcd_putsxy(0, y, str1); | ||
109 | lcd_putsxy(LCD_WIDTH - strlen(str2)*SYSFONT_WIDTH, y, str2); | ||
110 | } | ||
84 | 111 | ||
85 | default: | 112 | void recovery_menu(void) |
86 | break; | 113 | { |
87 | } | 114 | struct viewport vp = { |
88 | } | 115 | .x = 0, .y = SYSFONT_HEIGHT, |
116 | .width = LCD_WIDTH, | ||
117 | .height = LCD_HEIGHT - SYSFONT_HEIGHT*5, | ||
118 | }; | ||
119 | lcd_init_viewport(&vp); | ||
120 | |||
121 | struct bl_list list; | ||
122 | gui_list_init(&list, &vp); | ||
123 | list.num_items = ARRAYLEN(recovery_items); | ||
124 | list.selected_item = 1; /* first item is a heading */ | ||
125 | list.draw_item = recmenu_draw_item; | ||
89 | 126 | ||
90 | /* draw the selection marker */ | 127 | while(1) { |
91 | lcd_puts(0, top_line+selection, "=>"); | 128 | clearscreen(); |
129 | putcenter_y(0, "Rockbox recovery menu"); | ||
92 | 130 | ||
93 | /* draw the help text */ | 131 | /* draw the help text */ |
94 | int line = (LCD_HEIGHT - SYSFONT_HEIGHT)/SYSFONT_HEIGHT - 3; | 132 | int ypos = LCD_HEIGHT - 4*SYSFONT_HEIGHT; |
95 | put_help_line(line++, BL_DOWN_NAME "/" BL_UP_NAME, "move cursor"); | 133 | put_help_line(ypos, 0, BL_DOWN_NAME "/" BL_UP_NAME, "move cursor"); |
96 | put_help_line(line++, BL_SELECT_NAME, "select item"); | 134 | put_help_line(ypos, 1, BL_SELECT_NAME, "select item"); |
97 | put_help_line(line++, BL_QUIT_NAME, "power off"); | 135 | put_help_line(ypos, 2, BL_QUIT_NAME, "power off"); |
136 | |||
137 | /* draw the list */ | ||
138 | gui_list_draw(&list); | ||
98 | 139 | ||
99 | lcd_update(); | 140 | lcd_update(); |
100 | 141 | ||
101 | /* handle input */ | 142 | /* handle input */ |
102 | switch(get_button(TIMEOUT_BLOCK)) { | 143 | switch(get_button(TIMEOUT_BLOCK)) { |
103 | case BL_SELECT: { | 144 | case BL_SELECT: { |
104 | if(recovery_items[selection].action) | 145 | if(recovery_items[list.selected_item].action) |
105 | recovery_items[selection].action(); | 146 | recovery_items[list.selected_item].action(); |
106 | } break; | 147 | } break; |
107 | 148 | ||
108 | case BL_UP: | 149 | case BL_UP: |
109 | for(int i = selection-1; i >= 0; --i) { | 150 | recmenu_scroll(&list, -1); |
110 | if(recovery_items[i].action) { | ||
111 | selection = i; | ||
112 | break; | ||
113 | } | ||
114 | } | ||
115 | break; | 151 | break; |
116 | 152 | ||
117 | case BL_DOWN: | 153 | case BL_DOWN: |
118 | for(int i = selection+1; i < n_items; ++i) { | 154 | recmenu_scroll(&list, 1); |
119 | if(recovery_items[i].action) { | ||
120 | selection = i; | ||
121 | break; | ||
122 | } | ||
123 | } | ||
124 | break; | 155 | break; |
125 | 156 | ||
126 | case BL_QUIT: | 157 | case BL_QUIT: |