|
@@ -36,6 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
36
|
36
|
#include <ipxe/timer.h>
|
37
|
37
|
#include <ipxe/console.h>
|
38
|
38
|
#include <ipxe/ansicol.h>
|
|
39
|
+#include <ipxe/jumpscroll.h>
|
39
|
40
|
#include <ipxe/menu.h>
|
40
|
41
|
|
41
|
42
|
/* Screen layout */
|
|
@@ -50,12 +51,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
50
|
51
|
struct menu_ui {
|
51
|
52
|
/** Menu */
|
52
|
53
|
struct menu *menu;
|
53
|
|
- /** Number of menu items */
|
54
|
|
- unsigned int count;
|
55
|
|
- /** Currently selected item */
|
56
|
|
- int selected;
|
57
|
|
- /** First visible item */
|
58
|
|
- int first_visible;
|
|
54
|
+ /** Jump scroller */
|
|
55
|
+ struct jump_scroller scroll;
|
59
|
56
|
/** Timeout (0=indefinite) */
|
60
|
57
|
unsigned long timeout;
|
61
|
58
|
};
|
|
@@ -84,7 +81,7 @@ static struct menu_item * menu_item ( struct menu *menu, unsigned int index ) {
|
84
|
81
|
* @v ui Menu user interface
|
85
|
82
|
* @v index Index
|
86
|
83
|
*/
|
87
|
|
-static void draw_menu_item ( struct menu_ui *ui, int index ) {
|
|
84
|
+static void draw_menu_item ( struct menu_ui *ui, unsigned int index ) {
|
88
|
85
|
struct menu_item *item;
|
89
|
86
|
unsigned int row_offset;
|
90
|
87
|
char buf[ MENU_COLS + 1 /* NUL */ ];
|
|
@@ -94,7 +91,7 @@ static void draw_menu_item ( struct menu_ui *ui, int index ) {
|
94
|
91
|
size_t len;
|
95
|
92
|
|
96
|
93
|
/* Move to start of row */
|
97
|
|
- row_offset = ( index - ui->first_visible );
|
|
94
|
+ row_offset = ( index - ui->scroll.first );
|
98
|
95
|
move ( ( MENU_ROW + row_offset ), MENU_COL );
|
99
|
96
|
|
100
|
97
|
/* Get menu item */
|
|
@@ -106,7 +103,7 @@ static void draw_menu_item ( struct menu_ui *ui, int index ) {
|
106
|
103
|
color_set ( CPAIR_SEPARATOR, NULL );
|
107
|
104
|
|
108
|
105
|
/* Highlight if this is the selected item */
|
109
|
|
- if ( index == ui->selected ) {
|
|
106
|
+ if ( index == ui->scroll.current ) {
|
110
|
107
|
color_set ( CPAIR_SELECT, NULL );
|
111
|
108
|
attron ( A_BOLD );
|
112
|
109
|
}
|
|
@@ -125,7 +122,7 @@ static void draw_menu_item ( struct menu_ui *ui, int index ) {
|
125
|
122
|
snprintf ( timeout_buf, sizeof ( timeout_buf ), "(%ld)",
|
126
|
123
|
( ( ui->timeout + TICKS_PER_SEC - 1 ) /
|
127
|
124
|
TICKS_PER_SEC ) );
|
128
|
|
- if ( ( index == ui->selected ) && ( ui->timeout != 0 ) ) {
|
|
125
|
+ if ( ( index == ui->scroll.current ) && ( ui->timeout != 0 ) ) {
|
129
|
126
|
memcpy ( ( buf + MENU_COLS - MENU_PAD - timeout_len ),
|
130
|
127
|
timeout_buf, timeout_len );
|
131
|
128
|
}
|
|
@@ -154,24 +151,17 @@ static void draw_menu_item ( struct menu_ui *ui, int index ) {
|
154
|
151
|
static void draw_menu_items ( struct menu_ui *ui ) {
|
155
|
152
|
unsigned int i;
|
156
|
153
|
|
157
|
|
- /* Jump scroll to correct point in list */
|
158
|
|
- while ( ui->first_visible < ui->selected )
|
159
|
|
- ui->first_visible += MENU_ROWS;
|
160
|
|
- while ( ui->first_visible > ui->selected )
|
161
|
|
- ui->first_visible -= MENU_ROWS;
|
162
|
|
-
|
163
|
154
|
/* Draw ellipses before and/or after the list as necessary */
|
164
|
155
|
color_set ( CPAIR_SEPARATOR, NULL );
|
165
|
156
|
mvaddstr ( ( MENU_ROW - 1 ), ( MENU_COL + MENU_PAD ),
|
166
|
|
- ( ( ui->first_visible > 0 ) ? "..." : " " ) );
|
|
157
|
+ ( jump_scroll_is_first ( &ui->scroll ) ? " " : "..." ) );
|
167
|
158
|
mvaddstr ( ( MENU_ROW + MENU_ROWS ), ( MENU_COL + MENU_PAD ),
|
168
|
|
- ( ( ( ui->first_visible + MENU_ROWS ) < ui->count ) ?
|
169
|
|
- "..." : " " ) );
|
|
159
|
+ ( jump_scroll_is_last ( &ui->scroll ) ? " " : "..." ) );
|
170
|
160
|
color_set ( CPAIR_NORMAL, NULL );
|
171
|
161
|
|
172
|
162
|
/* Draw visible items */
|
173
|
163
|
for ( i = 0 ; i < MENU_ROWS ; i++ )
|
174
|
|
- draw_menu_item ( ui, ( ui->first_visible + i ) );
|
|
164
|
+ draw_menu_item ( ui, ( ui->scroll.first + i ) );
|
175
|
165
|
}
|
176
|
166
|
|
177
|
167
|
/**
|
|
@@ -184,8 +174,7 @@ static void draw_menu_items ( struct menu_ui *ui ) {
|
184
|
174
|
static int menu_loop ( struct menu_ui *ui, struct menu_item **selected ) {
|
185
|
175
|
struct menu_item *item;
|
186
|
176
|
unsigned long timeout;
|
187
|
|
- unsigned int delta;
|
188
|
|
- int current;
|
|
177
|
+ unsigned int previous;
|
189
|
178
|
int key;
|
190
|
179
|
int i;
|
191
|
180
|
int move;
|
|
@@ -194,7 +183,7 @@ static int menu_loop ( struct menu_ui *ui, struct menu_item **selected ) {
|
194
|
183
|
|
195
|
184
|
do {
|
196
|
185
|
/* Record current selection */
|
197
|
|
- current = ui->selected;
|
|
186
|
+ previous = ui->scroll.current;
|
198
|
187
|
|
199
|
188
|
/* Calculate timeout as remainder of current second */
|
200
|
189
|
timeout = ( ui->timeout % TICKS_PER_SEC );
|
|
@@ -213,27 +202,11 @@ static int menu_loop ( struct menu_ui *ui, struct menu_item **selected ) {
|
213
|
202
|
/* Cancel any timeout */
|
214
|
203
|
ui->timeout = 0;
|
215
|
204
|
|
216
|
|
- /* Handle key */
|
|
205
|
+ /* Handle scroll keys */
|
|
206
|
+ move = jump_scroll_key ( &ui->scroll, key );
|
|
207
|
+
|
|
208
|
+ /* Handle other keys */
|
217
|
209
|
switch ( key ) {
|
218
|
|
- case KEY_UP:
|
219
|
|
- move = -1;
|
220
|
|
- break;
|
221
|
|
- case KEY_DOWN:
|
222
|
|
- move = +1;
|
223
|
|
- break;
|
224
|
|
- case KEY_PPAGE:
|
225
|
|
- move = ( ui->first_visible - ui->selected - 1 );
|
226
|
|
- break;
|
227
|
|
- case KEY_NPAGE:
|
228
|
|
- move = ( ui->first_visible - ui->selected
|
229
|
|
- + MENU_ROWS );
|
230
|
|
- break;
|
231
|
|
- case KEY_HOME:
|
232
|
|
- move = -ui->count;
|
233
|
|
- break;
|
234
|
|
- case KEY_END:
|
235
|
|
- move = +ui->count;
|
236
|
|
- break;
|
237
|
210
|
case ESC:
|
238
|
211
|
case CTRL_C:
|
239
|
212
|
rc = -ECANCELED;
|
|
@@ -251,7 +224,7 @@ static int menu_loop ( struct menu_ui *ui, struct menu_item **selected ) {
|
251
|
224
|
i++;
|
252
|
225
|
continue;
|
253
|
226
|
}
|
254
|
|
- ui->selected = i;
|
|
227
|
+ ui->scroll.current = i;
|
255
|
228
|
if ( item->label ) {
|
256
|
229
|
chosen = 1;
|
257
|
230
|
} else {
|
|
@@ -264,31 +237,22 @@ static int menu_loop ( struct menu_ui *ui, struct menu_item **selected ) {
|
264
|
237
|
|
265
|
238
|
/* Move selection, if applicable */
|
266
|
239
|
while ( move ) {
|
267
|
|
- ui->selected += move;
|
268
|
|
- if ( ui->selected < 0 ) {
|
269
|
|
- ui->selected = 0;
|
270
|
|
- move = +1;
|
271
|
|
- } else if ( ui->selected >= ( int ) ui->count ) {
|
272
|
|
- ui->selected = ( ui->count - 1 );
|
273
|
|
- move = -1;
|
274
|
|
- }
|
275
|
|
- item = menu_item ( ui->menu, ui->selected );
|
|
240
|
+ move = jump_scroll_move ( &ui->scroll, move );
|
|
241
|
+ item = menu_item ( ui->menu, ui->scroll.current );
|
276
|
242
|
if ( item->label )
|
277
|
243
|
break;
|
278
|
|
- move = ( ( move > 0 ) ? +1 : -1 );
|
279
|
244
|
}
|
280
|
245
|
|
281
|
246
|
/* Redraw selection if necessary */
|
282
|
|
- if ( ( ui->selected != current ) || ( timeout != 0 ) ) {
|
283
|
|
- draw_menu_item ( ui, current );
|
284
|
|
- delta = ( ui->selected - ui->first_visible );
|
285
|
|
- if ( delta >= MENU_ROWS )
|
|
247
|
+ if ( ( ui->scroll.current != previous ) || ( timeout != 0 ) ) {
|
|
248
|
+ draw_menu_item ( ui, previous );
|
|
249
|
+ if ( jump_scroll ( &ui->scroll ) )
|
286
|
250
|
draw_menu_items ( ui );
|
287
|
|
- draw_menu_item ( ui, ui->selected );
|
|
251
|
+ draw_menu_item ( ui, ui->scroll.current );
|
288
|
252
|
}
|
289
|
253
|
|
290
|
254
|
/* Record selection */
|
291
|
|
- item = menu_item ( ui->menu, ui->selected );
|
|
255
|
+ item = menu_item ( ui->menu, ui->scroll.current );
|
292
|
256
|
assert ( item != NULL );
|
293
|
257
|
assert ( item->label != NULL );
|
294
|
258
|
*selected = item;
|
|
@@ -317,21 +281,22 @@ int show_menu ( struct menu *menu, unsigned long timeout,
|
317
|
281
|
/* Initialise UI */
|
318
|
282
|
memset ( &ui, 0, sizeof ( ui ) );
|
319
|
283
|
ui.menu = menu;
|
|
284
|
+ ui.scroll.rows = MENU_ROWS;
|
320
|
285
|
ui.timeout = timeout;
|
321
|
286
|
list_for_each_entry ( item, &menu->items, list ) {
|
322
|
287
|
if ( item->label ) {
|
323
|
288
|
if ( ! labelled_count )
|
324
|
|
- ui.selected = ui.count;
|
|
289
|
+ ui.scroll.current = ui.scroll.count;
|
325
|
290
|
labelled_count++;
|
326
|
291
|
if ( select ) {
|
327
|
292
|
if ( strcmp ( select, item->label ) == 0 )
|
328
|
|
- ui.selected = ui.count;
|
|
293
|
+ ui.scroll.current = ui.scroll.count;
|
329
|
294
|
} else {
|
330
|
295
|
if ( item->is_default )
|
331
|
|
- ui.selected = ui.count;
|
|
296
|
+ ui.scroll.current = ui.scroll.count;
|
332
|
297
|
}
|
333
|
298
|
}
|
334
|
|
- ui.count++;
|
|
299
|
+ ui.scroll.count++;
|
335
|
300
|
}
|
336
|
301
|
if ( ! labelled_count ) {
|
337
|
302
|
/* Menus with no labelled items cannot be selected
|
|
@@ -353,8 +318,9 @@ int show_menu ( struct menu *menu, unsigned long timeout,
|
353
|
318
|
snprintf ( buf, sizeof ( buf ), "%s", ui.menu->title );
|
354
|
319
|
mvprintw ( TITLE_ROW, ( ( COLS - strlen ( buf ) ) / 2 ), "%s", buf );
|
355
|
320
|
attroff ( A_BOLD );
|
|
321
|
+ jump_scroll ( &ui.scroll );
|
356
|
322
|
draw_menu_items ( &ui );
|
357
|
|
- draw_menu_item ( &ui, ui.selected );
|
|
323
|
+ draw_menu_item ( &ui, ui.scroll.current );
|
358
|
324
|
|
359
|
325
|
/* Enter main loop */
|
360
|
326
|
rc = menu_loop ( &ui, selected );
|