Root/
Source at commit 2188 created 11 years 3 months ago. By ifabio, Cards list update Preparing update for NVRAM Module | |
---|---|
1 | /*␊ |
2 | * menubox.c -- implements the menu box␊ |
3 | *␊ |
4 | * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)␊ |
5 | * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com)␊ |
6 | *␊ |
7 | * This program is free software; you can redistribute it and/or␊ |
8 | * modify it under the terms of the GNU General Public License␊ |
9 | * as published by the Free Software Foundation; either version 2␊ |
10 | * of the License, or (at your option) any later version.␊ |
11 | *␊ |
12 | * This program is distributed in the hope that it will be useful,␊ |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of␊ |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the␊ |
15 | * GNU General Public License for more details.␊ |
16 | *␊ |
17 | * You should have received a copy of the GNU General Public License␊ |
18 | * along with this program; if not, write to the Free Software␊ |
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.␊ |
20 | */␊ |
21 | ␊ |
22 | /*␊ |
23 | * Changes by Clifford Wolf (god@clifford.at)␊ |
24 | *␊ |
25 | * [ 1998-06-13 ]␊ |
26 | *␊ |
27 | * *) A bugfix for the Page-Down problem␊ |
28 | *␊ |
29 | * *) Formerly when I used Page Down and Page Up, the cursor would be set ␊ |
30 | * to the first position in the menu box. Now lxdialog is a bit␊ |
31 | * smarter and works more like other menu systems (just have a look at␊ |
32 | * it).␊ |
33 | *␊ |
34 | * *) Formerly if I selected something my scrolling would be broken because␊ |
35 | * lxdialog is re-invoked by the Menuconfig shell script, can't␊ |
36 | * remember the last scrolling position, and just sets it so that the␊ |
37 | * cursor is at the bottom of the box. Now it writes the temporary file␊ |
38 | * lxdialog.scrltmp which contains this information. The file is␊ |
39 | * deleted by lxdialog if the user leaves a submenu or enters a new␊ |
40 | * one, but it would be nice if Menuconfig could make another "rm -f"␊ |
41 | * just to be sure. Just try it out - you will recognise a difference!␊ |
42 | *␊ |
43 | * [ 1998-06-14 ]␊ |
44 | *␊ |
45 | * *) Now lxdialog is crash-safe against broken "lxdialog.scrltmp" files␊ |
46 | * and menus change their size on the fly.␊ |
47 | *␊ |
48 | * *) If for some reason the last scrolling position is not saved by␊ |
49 | * lxdialog, it sets the scrolling so that the selected item is in the␊ |
50 | * middle of the menu box, not at the bottom.␊ |
51 | *␊ |
52 | * 02 January 1999, Michael Elizabeth Chastain (mec@shout.net)␊ |
53 | * Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus.␊ |
54 | * This fixes a bug in Menuconfig where using ' ' to descend into menus␊ |
55 | * would leave mis-synchronized lxdialog.scrltmp files lying around,␊ |
56 | * fscanf would read in 'scroll', and eventually that value would get used.␊ |
57 | */␊ |
58 | ␊ |
59 | #include "dialog.h"␊ |
60 | ␊ |
61 | static int menu_width, item_x;␊ |
62 | ␊ |
63 | /*␊ |
64 | * Print menu item␊ |
65 | */␊ |
66 | static void do_print_item(WINDOW * win, const char *item, int line_y,␊ |
67 | int selected, int hotkey)␊ |
68 | {␊ |
69 | ␉int j;␊ |
70 | ␉char *menu_item = malloc(menu_width + 1);␊ |
71 | ␊ |
72 | ␉strncpy(menu_item, item, menu_width - item_x);␊ |
73 | ␉menu_item[menu_width - item_x] = '\0';␊ |
74 | ␉j = first_alpha(menu_item, "YyNnMmHh");␊ |
75 | ␊ |
76 | ␉/* Clear 'residue' of last item */␊ |
77 | ␉wattrset(win, dlg.menubox.atr);␊ |
78 | ␉wmove(win, line_y, 0);␊ |
79 | #if OLD_NCURSES␊ |
80 | ␉{␊ |
81 | ␉␉int i;␊ |
82 | ␉␉for (i = 0; i < menu_width; i++)␊ |
83 | ␉␉␉waddch(win, ' ');␊ |
84 | ␉}␊ |
85 | #else␊ |
86 | ␉wclrtoeol(win);␊ |
87 | #endif␊ |
88 | ␉wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);␊ |
89 | ␉mvwaddstr(win, line_y, item_x, menu_item);␊ |
90 | ␉if (hotkey) {␊ |
91 | ␉␉wattrset(win, selected ? dlg.tag_key_selected.atr␊ |
92 | ␉␉␉ : dlg.tag_key.atr);␊ |
93 | ␉␉mvwaddch(win, line_y, item_x + j, menu_item[j]);␊ |
94 | ␉}␊ |
95 | ␉if (selected) {␊ |
96 | ␉␉wmove(win, line_y, item_x + 1);␊ |
97 | ␉}␊ |
98 | ␉free(menu_item);␊ |
99 | ␉wrefresh(win);␊ |
100 | }␊ |
101 | ␊ |
102 | #define print_item(index, choice, selected)␉␉␉␉\␊ |
103 | do {␉␉␉␉␉␉␉␉␉\␊ |
104 | ␉item_set(index);␉␉␉␉␉␉\␊ |
105 | ␉do_print_item(menu, item_str(), choice, selected, !item_is_tag(':')); \␊ |
106 | } while (0)␊ |
107 | ␊ |
108 | /*␊ |
109 | * Print the scroll indicators.␊ |
110 | */␊ |
111 | static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x,␊ |
112 | ␉␉␉ int height)␊ |
113 | {␊ |
114 | ␉int cur_y, cur_x;␊ |
115 | ␊ |
116 | ␉getyx(win, cur_y, cur_x);␊ |
117 | ␊ |
118 | ␉wmove(win, y, x);␊ |
119 | ␊ |
120 | ␉if (scroll > 0) {␊ |
121 | ␉␉wattrset(win, dlg.uarrow.atr);␊ |
122 | ␉␉waddch(win, ACS_UARROW);␊ |
123 | ␉␉waddstr(win, "(-)");␊ |
124 | ␉} else {␊ |
125 | ␉␉wattrset(win, dlg.menubox.atr);␊ |
126 | ␉␉waddch(win, ACS_HLINE);␊ |
127 | ␉␉waddch(win, ACS_HLINE);␊ |
128 | ␉␉waddch(win, ACS_HLINE);␊ |
129 | ␉␉waddch(win, ACS_HLINE);␊ |
130 | ␉}␊ |
131 | ␊ |
132 | ␉y = y + height + 1;␊ |
133 | ␉wmove(win, y, x);␊ |
134 | ␉wrefresh(win);␊ |
135 | ␊ |
136 | ␉if ((height < item_no) && (scroll + height < item_no)) {␊ |
137 | ␉␉wattrset(win, dlg.darrow.atr);␊ |
138 | ␉␉waddch(win, ACS_DARROW);␊ |
139 | ␉␉waddstr(win, "(+)");␊ |
140 | ␉} else {␊ |
141 | ␉␉wattrset(win, dlg.menubox_border.atr);␊ |
142 | ␉␉waddch(win, ACS_HLINE);␊ |
143 | ␉␉waddch(win, ACS_HLINE);␊ |
144 | ␉␉waddch(win, ACS_HLINE);␊ |
145 | ␉␉waddch(win, ACS_HLINE);␊ |
146 | ␉}␊ |
147 | ␊ |
148 | ␉wmove(win, cur_y, cur_x);␊ |
149 | ␉wrefresh(win);␊ |
150 | }␊ |
151 | ␊ |
152 | /*␊ |
153 | * Display the termination buttons.␊ |
154 | */␊ |
155 | static void print_buttons(WINDOW * win, int height, int width, int selected)␊ |
156 | {␊ |
157 | ␉int x = width / 2 - 16;␊ |
158 | ␉int y = height - 2;␊ |
159 | ␊ |
160 | ␉print_button(win, gettext("Select"), y, x, selected == 0);␊ |
161 | ␉print_button(win, gettext(" Exit "), y, x + 12, selected == 1);␊ |
162 | ␉print_button(win, gettext(" Help "), y, x + 24, selected == 2);␊ |
163 | ␊ |
164 | ␉wmove(win, y, x + 1 + 12 * selected);␊ |
165 | ␉wrefresh(win);␊ |
166 | }␊ |
167 | ␊ |
168 | /* scroll up n lines (n may be negative) */␊ |
169 | static void do_scroll(WINDOW *win, int *scroll, int n)␊ |
170 | {␊ |
171 | ␉/* Scroll menu up */␊ |
172 | ␉scrollok(win, TRUE);␊ |
173 | ␉wscrl(win, n);␊ |
174 | ␉scrollok(win, FALSE);␊ |
175 | ␉*scroll = *scroll + n;␊ |
176 | ␉wrefresh(win);␊ |
177 | }␊ |
178 | ␊ |
179 | /*␊ |
180 | * Display a menu for choosing among a number of options␊ |
181 | */␊ |
182 | int dialog_menu(const char *title, const char *prompt,␊ |
183 | const void *selected, int *s_scroll)␊ |
184 | {␊ |
185 | ␉int i, j, x, y, box_x, box_y;␊ |
186 | ␉int height, width, menu_height;␊ |
187 | ␉int key = 0, button = 0, scroll = 0, choice = 0;␊ |
188 | ␉int first_item = 0, max_choice;␊ |
189 | ␉WINDOW *dialog, *menu;␊ |
190 | ␊ |
191 | do_resize:␊ |
192 | ␉height = getmaxy(stdscr);␊ |
193 | ␉width = getmaxx(stdscr);␊ |
194 | ␉if (height < 15 || width < 65)␊ |
195 | ␉␉return -ERRDISPLAYTOOSMALL;␊ |
196 | ␊ |
197 | ␉height -= 4;␊ |
198 | ␉width -= 5;␊ |
199 | ␉menu_height = height - 10;␊ |
200 | ␊ |
201 | ␉max_choice = MIN(menu_height, item_count());␊ |
202 | ␊ |
203 | ␉/* center dialog box on screen */␊ |
204 | ␉x = (COLS - width) / 2;␊ |
205 | ␉y = (LINES - height) / 2;␊ |
206 | ␊ |
207 | ␉draw_shadow(stdscr, y, x, height, width);␊ |
208 | ␊ |
209 | ␉dialog = newwin(height, width, y, x);␊ |
210 | ␉keypad(dialog, TRUE);␊ |
211 | ␊ |
212 | ␉draw_box(dialog, 0, 0, height, width,␊ |
213 | ␉␉ dlg.dialog.atr, dlg.border.atr);␊ |
214 | ␉wattrset(dialog, dlg.border.atr);␊ |
215 | ␉mvwaddch(dialog, height - 3, 0, ACS_LTEE);␊ |
216 | ␉for (i = 0; i < width - 2; i++)␊ |
217 | ␉␉waddch(dialog, ACS_HLINE);␊ |
218 | ␉wattrset(dialog, dlg.dialog.atr);␊ |
219 | ␉wbkgdset(dialog, dlg.dialog.atr & A_COLOR);␊ |
220 | ␉waddch(dialog, ACS_RTEE);␊ |
221 | ␊ |
222 | ␉print_title(dialog, title, width);␊ |
223 | ␊ |
224 | ␉wattrset(dialog, dlg.dialog.atr);␊ |
225 | ␉print_autowrap(dialog, prompt, width - 2, 1, 3);␊ |
226 | ␊ |
227 | ␉menu_width = width - 6;␊ |
228 | ␉box_y = height - menu_height - 5;␊ |
229 | ␉box_x = (width - menu_width) / 2 - 1;␊ |
230 | ␊ |
231 | ␉/* create new window for the menu */␊ |
232 | ␉menu = subwin(dialog, menu_height, menu_width,␊ |
233 | ␉␉ y + box_y + 1, x + box_x + 1);␊ |
234 | ␉keypad(menu, TRUE);␊ |
235 | ␊ |
236 | ␉/* draw a box around the menu items */␊ |
237 | ␉draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2,␊ |
238 | ␉␉ dlg.menubox_border.atr, dlg.menubox.atr);␊ |
239 | ␊ |
240 | ␉if (menu_width >= 80)␊ |
241 | ␉␉item_x = (menu_width - 70) / 2;␊ |
242 | ␉else␊ |
243 | ␉␉item_x = 4;␊ |
244 | ␊ |
245 | ␉/* Set choice to default item */␊ |
246 | ␉item_foreach()␊ |
247 | ␉␉if (selected && (selected == item_data()))␊ |
248 | ␉␉␉choice = item_n();␊ |
249 | ␉/* get the saved scroll info */␊ |
250 | ␉scroll = *s_scroll;␊ |
251 | ␉if ((scroll <= choice) && (scroll + max_choice > choice) &&␊ |
252 | ␉ (scroll >= 0) && (scroll + max_choice <= item_count())) {␊ |
253 | ␉␉first_item = scroll;␊ |
254 | ␉␉choice = choice - scroll;␊ |
255 | ␉} else {␊ |
256 | ␉␉scroll = 0;␊ |
257 | ␉}␊ |
258 | ␉if ((choice >= max_choice)) {␊ |
259 | ␉␉if (choice >= item_count() - max_choice / 2)␊ |
260 | ␉␉␉scroll = first_item = item_count() - max_choice;␊ |
261 | ␉␉else␊ |
262 | ␉␉␉scroll = first_item = choice - max_choice / 2;␊ |
263 | ␉␉choice = choice - scroll;␊ |
264 | ␉}␊ |
265 | ␊ |
266 | ␉/* Print the menu */␊ |
267 | ␉for (i = 0; i < max_choice; i++) {␊ |
268 | ␉␉print_item(first_item + i, i, i == choice);␊ |
269 | ␉}␊ |
270 | ␊ |
271 | ␉wnoutrefresh(menu);␊ |
272 | ␊ |
273 | ␉print_arrows(dialog, item_count(), scroll,␊ |
274 | ␉␉ box_y, box_x + item_x + 1, menu_height);␊ |
275 | ␊ |
276 | ␉print_buttons(dialog, height, width, 0);␊ |
277 | ␉wmove(menu, choice, item_x + 1);␊ |
278 | ␉wrefresh(menu);␊ |
279 | ␊ |
280 | ␉while (key != KEY_ESC) {␊ |
281 | ␉␉key = wgetch(menu);␊ |
282 | ␊ |
283 | ␉␉if (key < 256 && isalpha(key))␊ |
284 | ␉␉␉key = tolower(key);␊ |
285 | ␊ |
286 | ␉␉if (strchr("ynmh", key))␊ |
287 | ␉␉␉i = max_choice;␊ |
288 | ␉␉else {␊ |
289 | ␉␉␉for (i = choice + 1; i < max_choice; i++) {␊ |
290 | ␉␉␉␉item_set(scroll + i);␊ |
291 | ␉␉␉␉j = first_alpha(item_str(), "YyNnMmHh");␊ |
292 | ␉␉␉␉if (key == tolower(item_str()[j]))␊ |
293 | ␉␉␉␉␉break;␊ |
294 | ␉␉␉}␊ |
295 | ␉␉␉if (i == max_choice)␊ |
296 | ␉␉␉␉for (i = 0; i < max_choice; i++) {␊ |
297 | ␉␉␉␉␉item_set(scroll + i);␊ |
298 | ␉␉␉␉␉j = first_alpha(item_str(), "YyNnMmHh");␊ |
299 | ␉␉␉␉␉if (key == tolower(item_str()[j]))␊ |
300 | ␉␉␉␉␉␉break;␊ |
301 | ␉␉␉␉}␊ |
302 | ␉␉}␊ |
303 | ␊ |
304 | ␉␉if (i < max_choice ||␊ |
305 | ␉␉ key == KEY_UP || key == KEY_DOWN ||␊ |
306 | ␉␉ key == '-' || key == '+' ||␊ |
307 | ␉␉ key == KEY_PPAGE || key == KEY_NPAGE) {␊ |
308 | ␉␉␉/* Remove highligt of current item */␊ |
309 | ␉␉␉print_item(scroll + choice, choice, FALSE);␊ |
310 | ␊ |
311 | ␉␉␉if (key == KEY_UP || key == '-') {␊ |
312 | ␉␉␉␉if (choice < 2 && scroll) {␊ |
313 | ␉␉␉␉␉/* Scroll menu down */␊ |
314 | ␉␉␉␉␉do_scroll(menu, &scroll, -1);␊ |
315 | ␊ |
316 | ␉␉␉␉␉print_item(scroll, 0, FALSE);␊ |
317 | ␉␉␉␉} else␊ |
318 | ␉␉␉␉␉choice = MAX(choice - 1, 0);␊ |
319 | ␊ |
320 | ␉␉␉} else if (key == KEY_DOWN || key == '+') {␊ |
321 | ␉␉␉␉print_item(scroll+choice, choice, FALSE);␊ |
322 | ␊ |
323 | ␉␉␉␉if ((choice > max_choice - 3) &&␊ |
324 | ␉␉␉␉ (scroll + max_choice < item_count())) {␊ |
325 | ␉␉␉␉␉/* Scroll menu up */␊ |
326 | ␉␉␉␉␉do_scroll(menu, &scroll, 1);␊ |
327 | ␊ |
328 | ␉␉␉␉␉print_item(scroll+max_choice - 1,␊ |
329 | ␉␉␉␉␉␉ max_choice - 1, FALSE);␊ |
330 | ␉␉␉␉} else␊ |
331 | ␉␉␉␉␉choice = MIN(choice + 1, max_choice - 1);␊ |
332 | ␊ |
333 | ␉␉␉} else if (key == KEY_PPAGE) {␊ |
334 | ␉␉␉␉scrollok(menu, TRUE);␊ |
335 | ␉␉␉␉for (i = 0; (i < max_choice); i++) {␊ |
336 | ␉␉␉␉␉if (scroll > 0) {␊ |
337 | ␉␉␉␉␉␉do_scroll(menu, &scroll, -1);␊ |
338 | ␉␉␉␉␉␉print_item(scroll, 0, FALSE);␊ |
339 | ␉␉␉␉␉} else {␊ |
340 | ␉␉␉␉␉␉if (choice > 0)␊ |
341 | ␉␉␉␉␉␉␉choice--;␊ |
342 | ␉␉␉␉␉}␊ |
343 | ␉␉␉␉}␊ |
344 | ␊ |
345 | ␉␉␉} else if (key == KEY_NPAGE) {␊ |
346 | ␉␉␉␉for (i = 0; (i < max_choice); i++) {␊ |
347 | ␉␉␉␉␉if (scroll + max_choice < item_count()) {␊ |
348 | ␉␉␉␉␉␉do_scroll(menu, &scroll, 1);␊ |
349 | ␉␉␉␉␉␉print_item(scroll+max_choice-1,␊ |
350 | ␉␉␉␉␉␉␉ max_choice - 1, FALSE);␊ |
351 | ␉␉␉␉␉} else {␊ |
352 | ␉␉␉␉␉␉if (choice + 1 < max_choice)␊ |
353 | ␉␉␉␉␉␉␉choice++;␊ |
354 | ␉␉␉␉␉}␊ |
355 | ␉␉␉␉}␊ |
356 | ␉␉␉} else␊ |
357 | ␉␉␉␉choice = i;␊ |
358 | ␊ |
359 | ␉␉␉print_item(scroll + choice, choice, TRUE);␊ |
360 | ␊ |
361 | ␉␉␉print_arrows(dialog, item_count(), scroll,␊ |
362 | ␉␉␉␉ box_y, box_x + item_x + 1, menu_height);␊ |
363 | ␊ |
364 | ␉␉␉wnoutrefresh(dialog);␊ |
365 | ␉␉␉wrefresh(menu);␊ |
366 | ␊ |
367 | ␉␉␉continue;␉/* wait for another key press */␊ |
368 | ␉␉}␊ |
369 | ␊ |
370 | ␉␉switch (key) {␊ |
371 | ␉␉case KEY_LEFT:␊ |
372 | ␉␉case TAB:␊ |
373 | ␉␉case KEY_RIGHT:␊ |
374 | ␉␉␉button = ((key == KEY_LEFT ? --button : ++button) < 0)␊ |
375 | ␉␉␉ ? 2 : (button > 2 ? 0 : button);␊ |
376 | ␊ |
377 | ␉␉␉print_buttons(dialog, height, width, button);␊ |
378 | ␉␉␉wrefresh(menu);␊ |
379 | ␉␉␉break;␊ |
380 | ␉␉case ' ':␊ |
381 | ␉␉case 's':␊ |
382 | ␉␉case 'y':␊ |
383 | ␉␉case 'n':␊ |
384 | ␉␉case 'm':␊ |
385 | ␉␉case '/':␊ |
386 | ␉␉case 'h':␊ |
387 | ␉␉case '?':␊ |
388 | ␉␉case 'z':␊ |
389 | ␉␉case '\n':␊ |
390 | ␉␉␉/* save scroll info */␊ |
391 | ␉␉␉*s_scroll = scroll;␊ |
392 | ␉␉␉delwin(menu);␊ |
393 | ␉␉␉delwin(dialog);␊ |
394 | ␉␉␉item_set(scroll + choice);␊ |
395 | ␉␉␉item_set_selected(1);␊ |
396 | ␉␉␉switch (key) {␊ |
397 | ␉␉␉case 'h':␊ |
398 | ␉␉␉case '?':␊ |
399 | ␉␉␉␉return 2;␊ |
400 | ␉␉␉case 's':␊ |
401 | ␉␉␉case 'y':␊ |
402 | ␉␉␉␉return 3;␊ |
403 | ␉␉␉case 'n':␊ |
404 | ␉␉␉␉return 4;␊ |
405 | ␉␉␉case 'm':␊ |
406 | ␉␉␉␉return 5;␊ |
407 | ␉␉␉case ' ':␊ |
408 | ␉␉␉␉return 6;␊ |
409 | ␉␉␉case '/':␊ |
410 | ␉␉␉␉return 7;␊ |
411 | ␉␉␉case 'z':␊ |
412 | ␉␉␉␉return 8;␊ |
413 | ␉␉␉case '\n':␊ |
414 | ␉␉␉␉return button;␊ |
415 | ␉␉␉}␊ |
416 | ␉␉␉return 0;␊ |
417 | ␉␉case 'e':␊ |
418 | ␉␉case 'x':␊ |
419 | ␉␉␉key = KEY_ESC;␊ |
420 | ␉␉␉break;␊ |
421 | ␉␉case KEY_ESC:␊ |
422 | ␉␉␉key = on_key_esc(menu);␊ |
423 | ␉␉␉break;␊ |
424 | ␉␉case KEY_RESIZE:␊ |
425 | ␉␉␉on_key_resize();␊ |
426 | ␉␉␉delwin(menu);␊ |
427 | ␉␉␉delwin(dialog);␊ |
428 | ␉␉␉goto do_resize;␊ |
429 | ␉␉}␊ |
430 | ␉}␊ |
431 | ␉delwin(menu);␊ |
432 | ␉delwin(dialog);␊ |
433 | ␉return key;␉␉/* ESC pressed */␊ |
434 | }␊ |
435 |