Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


imported SEABIOS source tree
[palacios.git] / bios / seabios / tools / kconfig / lxdialog / menubox.c
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 }