base/config/kconfig/lxdialog/menubox.c

Go to the documentation of this file.
00001 /* 00002 * menubox.c -- implements the menu box 00003 * 00004 * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) 00005 * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com) 00006 * 00007 * This program is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU General Public License 00009 * as published by the Free Software Foundation; either version 2 00010 * of the License, or (at your option) any later version. 00011 * 00012 * This program is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU General Public License 00018 * along with this program; if not, write to the Free Software 00019 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00020 */ 00021 00022 /* 00023 * Changes by Clifford Wolf (god@clifford.at) 00024 * 00025 * [ 1998-06-13 ] 00026 * 00027 * *) A bugfix for the Page-Down problem 00028 * 00029 * *) Formerly when I used Page Down and Page Up, the cursor would be set 00030 * to the first position in the menu box. Now lxdialog is a bit 00031 * smarter and works more like other menu systems (just have a look at 00032 * it). 00033 * 00034 * *) Formerly if I selected something my scrolling would be broken because 00035 * lxdialog is re-invoked by the Menuconfig shell script, can't 00036 * remember the last scrolling position, and just sets it so that the 00037 * cursor is at the bottom of the box. Now it writes the temporary file 00038 * lxdialog.scrltmp which contains this information. The file is 00039 * deleted by lxdialog if the user leaves a submenu or enters a new 00040 * one, but it would be nice if Menuconfig could make another "rm -f" 00041 * just to be sure. Just try it out - you will recognise a difference! 00042 * 00043 * [ 1998-06-14 ] 00044 * 00045 * *) Now lxdialog is crash-safe against broken "lxdialog.scrltmp" files 00046 * and menus change their size on the fly. 00047 * 00048 * *) If for some reason the last scrolling position is not saved by 00049 * lxdialog, it sets the scrolling so that the selected item is in the 00050 * middle of the menu box, not at the bottom. 00051 * 00052 * 02 January 1999, Michael Elizabeth Chastain (mec@shout.net) 00053 * Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus. 00054 * This fixes a bug in Menuconfig where using ' ' to descend into menus 00055 * would leave mis-synchronized lxdialog.scrltmp files lying around, 00056 * fscanf would read in 'scroll', and eventually that value would get used. 00057 */ 00058 00059 #include "dialog.h" 00060 00061 static int menu_width, item_x; 00062 00063 /* 00064 * Print menu item 00065 */ 00066 static void 00067 print_item (WINDOW * win, const char *item, int choice, int selected, int hotkey) 00068 { 00069 int j; 00070 char menu_item[menu_width+1]; 00071 00072 strncpy(menu_item, item, menu_width); 00073 menu_item[menu_width] = 0; 00074 j = first_alpha(menu_item, "YyNnMm"); 00075 00076 /* Clear 'residue' of last item */ 00077 wattrset (win, menubox_attr); 00078 wmove (win, choice, 0); 00079 #if OLD_NCURSES 00080 { 00081 int i; 00082 for (i = 0; i < menu_width; i++) 00083 waddch (win, ' '); 00084 } 00085 #else 00086 wclrtoeol(win); 00087 #endif 00088 wattrset (win, selected ? item_selected_attr : item_attr); 00089 mvwaddstr (win, choice, item_x, menu_item); 00090 if (hotkey) { 00091 wattrset (win, selected ? tag_key_selected_attr : tag_key_attr); 00092 mvwaddch(win, choice, item_x+j, menu_item[j]); 00093 } 00094 if (selected) { 00095 wmove (win, choice, item_x+1); 00096 wrefresh (win); 00097 } 00098 } 00099 00100 /* 00101 * Print the scroll indicators. 00102 */ 00103 static void 00104 print_arrows (WINDOW * win, int item_no, int scroll, 00105 int y, int x, int height) 00106 { 00107 int cur_y, cur_x; 00108 00109 getyx(win, cur_y, cur_x); 00110 00111 wmove(win, y, x); 00112 00113 if (scroll > 0) { 00114 wattrset (win, uarrow_attr); 00115 waddch (win, ACS_UARROW); 00116 waddstr (win, "(-)"); 00117 } 00118 else { 00119 wattrset (win, menubox_attr); 00120 waddch (win, ACS_HLINE); 00121 waddch (win, ACS_HLINE); 00122 waddch (win, ACS_HLINE); 00123 waddch (win, ACS_HLINE); 00124 } 00125 00126 y = y + height + 1; 00127 wmove(win, y, x); 00128 00129 if ((height < item_no) && (scroll + height < item_no)) { 00130 wattrset (win, darrow_attr); 00131 waddch (win, ACS_DARROW); 00132 waddstr (win, "(+)"); 00133 } 00134 else { 00135 wattrset (win, menubox_border_attr); 00136 waddch (win, ACS_HLINE); 00137 waddch (win, ACS_HLINE); 00138 waddch (win, ACS_HLINE); 00139 waddch (win, ACS_HLINE); 00140 } 00141 00142 wmove(win, cur_y, cur_x); 00143 } 00144 00145 /* 00146 * Display the termination buttons. 00147 */ 00148 static void 00149 print_buttons (WINDOW *win, int height, int width, int selected) 00150 { 00151 int x = width / 2 - 16; 00152 int y = height - 2; 00153 00154 print_button (win, "Select", y, x, selected == 0); 00155 print_button (win, " Exit ", y, x + 12, selected == 1); 00156 print_button (win, " Help ", y, x + 24, selected == 2); 00157 00158 wmove(win, y, x+1+12*selected); 00159 wrefresh (win); 00160 } 00161 00162 /* 00163 * Display a menu for choosing among a number of options 00164 */ 00165 int 00166 dialog_menu (const char *title, const char *prompt, int height, int width, 00167 int menu_height, const char *current, int item_no, 00168 const char * const * items) 00169 00170 { 00171 int i, j, x, y, box_x, box_y; 00172 int key = 0, button = 0, scroll = 0, choice = 0, first_item = 0, max_choice; 00173 WINDOW *dialog, *menu; 00174 FILE *f; 00175 00176 max_choice = MIN (menu_height, item_no); 00177 00178 /* center dialog box on screen */ 00179 x = (COLS - width) / 2; 00180 y = (LINES - height) / 2; 00181 00182 draw_shadow (stdscr, y, x, height, width); 00183 00184 dialog = newwin (height, width, y, x); 00185 keypad (dialog, TRUE); 00186 00187 draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr); 00188 wattrset (dialog, border_attr); 00189 mvwaddch (dialog, height - 3, 0, ACS_LTEE); 00190 for (i = 0; i < width - 2; i++) 00191 waddch (dialog, ACS_HLINE); 00192 wattrset (dialog, dialog_attr); 00193 wbkgdset (dialog, dialog_attr & A_COLOR); 00194 waddch (dialog, ACS_RTEE); 00195 00196 if (title != NULL && strlen(title) >= width-2 ) { 00197 /* truncate long title -- mec */ 00198 char * title2 = malloc(width-2+1); 00199 memcpy( title2, title, width-2 ); 00200 title2[width-2] = '\0'; 00201 title = title2; 00202 } 00203 00204 if (title != NULL) { 00205 wattrset (dialog, title_attr); 00206 mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' '); 00207 waddstr (dialog, (char *)title); 00208 waddch (dialog, ' '); 00209 } 00210 00211 wattrset (dialog, dialog_attr); 00212 print_autowrap (dialog, prompt, width - 2, 1, 3); 00213 00214 menu_width = width - 6; 00215 box_y = height - menu_height - 5; 00216 box_x = (width - menu_width) / 2 - 1; 00217 00218 /* create new window for the menu */ 00219 menu = subwin (dialog, menu_height, menu_width, 00220 y + box_y + 1, x + box_x + 1); 00221 keypad (menu, TRUE); 00222 00223 /* draw a box around the menu items */ 00224 draw_box (dialog, box_y, box_x, menu_height + 2, menu_width + 2, 00225 menubox_border_attr, menubox_attr); 00226 00227 /* 00228 * Find length of longest item in order to center menu. 00229 * Set 'choice' to default item. 00230 */ 00231 item_x = 0; 00232 for (i = 0; i < item_no; i++) { 00233 item_x = MAX (item_x, MIN(menu_width, strlen (items[i * 2 + 1]) + 2)); 00234 if (strcmp(current, items[i*2]) == 0) choice = i; 00235 } 00236 00237 item_x = (menu_width - item_x) / 2; 00238 00239 /* get the scroll info from the temp file */ 00240 if ( (f=fopen("lxdialog.scrltmp","r")) != NULL ) { 00241 if ( (fscanf(f,"%d\n",&scroll) == 1) && (scroll <= choice) && 00242 (scroll+max_choice > choice) && (scroll >= 0) && 00243 (scroll+max_choice <= item_no) ) { 00244 first_item = scroll; 00245 choice = choice - scroll; 00246 fclose(f); 00247 } else { 00248 scroll=0; 00249 remove("lxdialog.scrltmp"); 00250 fclose(f); 00251 f=NULL; 00252 } 00253 } 00254 if ( (choice >= max_choice) || (f==NULL && choice >= max_choice/2) ) { 00255 if (choice >= item_no-max_choice/2) 00256 scroll = first_item = item_no-max_choice; 00257 else 00258 scroll = first_item = choice - max_choice/2; 00259 choice = choice - scroll; 00260 } 00261 00262 /* Print the menu */ 00263 for (i=0; i < max_choice; i++) { 00264 print_item (menu, items[(first_item + i) * 2 + 1], i, i == choice, 00265 (items[(first_item + i)*2][0] != ':')); 00266 } 00267 00268 wnoutrefresh (menu); 00269 00270 print_arrows(dialog, item_no, scroll, 00271 box_y, box_x+item_x+1, menu_height); 00272 00273 print_buttons (dialog, height, width, 0); 00274 wmove (menu, choice, item_x+1); 00275 wrefresh (menu); 00276 00277 while (key != ESC) { 00278 key = wgetch(menu); 00279 00280 if (key < 256 && isalpha(key)) key = tolower(key); 00281 00282 if (strchr("ynm", key)) 00283 i = max_choice; 00284 else { 00285 for (i = choice+1; i < max_choice; i++) { 00286 j = first_alpha(items[(scroll+i)*2+1], "YyNnMm"); 00287 if (key == tolower(items[(scroll+i)*2+1][j])) 00288 break; 00289 } 00290 if (i == max_choice) 00291 for (i = 0; i < max_choice; i++) { 00292 j = first_alpha(items[(scroll+i)*2+1], "YyNnMm"); 00293 if (key == tolower(items[(scroll+i)*2+1][j])) 00294 break; 00295 } 00296 } 00297 00298 if (i < max_choice || 00299 key == KEY_UP || key == KEY_DOWN || 00300 key == '-' || key == '+' || 00301 key == KEY_PPAGE || key == KEY_NPAGE) { 00302 00303 print_item (menu, items[(scroll+choice)*2+1], choice, FALSE, 00304 (items[(scroll+choice)*2][0] != ':')); 00305 00306 if (key == KEY_UP || key == '-') { 00307 if (choice < 2 && scroll) { 00308 /* Scroll menu down */ 00309 scrollok (menu, TRUE); 00310 wscrl (menu, -1); 00311 scrollok (menu, FALSE); 00312 00313 scroll--; 00314 00315 print_item (menu, items[scroll * 2 + 1], 0, FALSE, 00316 (items[scroll*2][0] != ':')); 00317 } else 00318 choice = MAX(choice - 1, 0); 00319 00320 } else if (key == KEY_DOWN || key == '+') { 00321 00322 print_item (menu, items[(scroll+choice)*2+1], choice, FALSE, 00323 (items[(scroll+choice)*2][0] != ':')); 00324 00325 if ((choice > max_choice-3) && 00326 (scroll + max_choice < item_no) 00327 ) { 00328 /* Scroll menu up */ 00329 scrollok (menu, TRUE); 00330 scroll (menu); 00331 scrollok (menu, FALSE); 00332 00333 scroll++; 00334 00335 print_item (menu, items[(scroll+max_choice-1)*2+1], 00336 max_choice-1, FALSE, 00337 (items[(scroll+max_choice-1)*2][0] != ':')); 00338 } else 00339 choice = MIN(choice+1, max_choice-1); 00340 00341 } else if (key == KEY_PPAGE) { 00342 scrollok (menu, TRUE); 00343 for (i=0; (i < max_choice); i++) { 00344 if (scroll > 0) { 00345 wscrl (menu, -1); 00346 scroll--; 00347 print_item (menu, items[scroll * 2 + 1], 0, FALSE, 00348 (items[scroll*2][0] != ':')); 00349 } else { 00350 if (choice > 0) 00351 choice--; 00352 } 00353 } 00354 scrollok (menu, FALSE); 00355 00356 } else if (key == KEY_NPAGE) { 00357 for (i=0; (i < max_choice); i++) { 00358 if (scroll+max_choice < item_no) { 00359 scrollok (menu, TRUE); 00360 scroll(menu); 00361 scrollok (menu, FALSE); 00362 scroll++; 00363 print_item (menu, items[(scroll+max_choice-1)*2+1], 00364 max_choice-1, FALSE, 00365 (items[(scroll+max_choice-1)*2][0] != ':')); 00366 } else { 00367 if (choice+1 < max_choice) 00368 choice++; 00369 } 00370 } 00371 00372 } else 00373 choice = i; 00374 00375 print_item (menu, items[(scroll+choice)*2+1], choice, TRUE, 00376 (items[(scroll+choice)*2][0] != ':')); 00377 00378 print_arrows(dialog, item_no, scroll, 00379 box_y, box_x+item_x+1, menu_height); 00380 00381 wnoutrefresh (dialog); 00382 wrefresh (menu); 00383 00384 continue; /* wait for another key press */ 00385 } 00386 00387 switch (key) { 00388 case KEY_LEFT: 00389 case TAB: 00390 case KEY_RIGHT: 00391 button = ((key == KEY_LEFT ? --button : ++button) < 0) 00392 ? 2 : (button > 2 ? 0 : button); 00393 00394 print_buttons(dialog, height, width, button); 00395 wrefresh (menu); 00396 break; 00397 case ' ': 00398 case 's': 00399 case 'y': 00400 case 'n': 00401 case 'm': 00402 /* save scroll info */ 00403 if ( (f=fopen("lxdialog.scrltmp","w")) != NULL ) { 00404 fprintf(f,"%d\n",scroll); 00405 fclose(f); 00406 } 00407 delwin (dialog); 00408 fprintf(stderr, "%s\n", items[(scroll + choice) * 2]); 00409 switch (key) { 00410 case 's': return 3; 00411 case 'y': return 3; 00412 case 'n': return 4; 00413 case 'm': return 5; 00414 case ' ': return 6; 00415 } 00416 return 0; 00417 case 'h': 00418 case '?': 00419 button = 2; 00420 case '\n': 00421 delwin (dialog); 00422 if (button == 2) 00423 fprintf(stderr, "%s \"%s\"\n", 00424 items[(scroll + choice) * 2], 00425 items[(scroll + choice) * 2 + 1] + 00426 first_alpha(items[(scroll + choice) * 2 + 1],"")); 00427 else 00428 fprintf(stderr, "%s\n", items[(scroll + choice) * 2]); 00429 00430 remove("lxdialog.scrltmp"); 00431 return button; 00432 case 'e': 00433 case 'x': 00434 key = ESC; 00435 case ESC: 00436 break; 00437 } 00438 } 00439 00440 delwin (dialog); 00441 remove("lxdialog.scrltmp"); 00442 return -1; /* ESC pressed */ 00443 }

Generated on Thu Nov 20 11:49:48 2008 for RTAI API by doxygen 1.3.8