menu_sys.def revision 1.6
1/* $NetBSD: menu_sys.def,v 1.6 1998/06/24 14:44:52 phil Exp $ */ 2 3/* 4 * Copyright 1997 Piermont Information Systems Inc. 5 * All rights reserved. 6 * 7 * Written by Philip A. Nelson for Piermont Information Systems Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software develooped for the NetBSD Project by 20 * Piermont Information Systems Inc. 21 * 4. The name of Piermont Information Systems Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS'' 26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE 29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 35 * THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 */ 38 39/* menu_sys.defs -- Menu system standard routines. */ 40 41#include <string.h> 42#include <ctype.h> 43 44#define REQ_EXECUTE 1000 45#define REQ_NEXT_ITEM 1001 46#define REQ_PREV_ITEM 1002 47#define REQ_REDISPLAY 1003 48 49#define KEYPAD_DOWN_ARROW 256 50#define KEYPAD_UP_ARROW 257 51 52#define MAX(x,y) ((x)>(y)?(x):(y)) 53 54/* Initialization state. */ 55static int __menu_init = 0; 56int __m_endwin = 0; 57static int max_lines = 0; 58 59/* prototypes for in here! */ 60 61static void init_menu (struct menudesc *m); 62static void post_menu (struct menudesc *m); 63static void process_help (struct menudesc *m, int num); 64static void process_req (struct menudesc *m, int num, int req); 65static void mbeep (void); 66static int menucmd (WINDOW *w); 67 68#ifndef NULL 69#define NULL (void *)0 70#endif 71 72/* menu system processing routines */ 73 74static void mbeep (void) 75{ 76 fprintf (stderr,"\a"); 77} 78 79static int mgetch(WINDOW *w) 80{ 81 static char buf[20]; 82 static int num = 0; 83 84 int i, ret; 85 86 for (i=0; i< strlen(KD); i++) { 87 if (i >= num) 88 buf[num++] = wgetch(w); 89 if (buf[i] != KD[i]) 90 break; 91 } 92 if (i == strlen(KD)) { 93 num = 0; 94 return KEYPAD_DOWN_ARROW; 95 } 96 97 for (i=0; i< strlen(KU); i++) { 98 if (i >= num) 99 buf[num++] = wgetch(w); 100 if (buf[i] != KU[i]) 101 break; 102 } 103 if (i == strlen(KU)) { 104 num = 0; 105 return KEYPAD_UP_ARROW; 106 } 107 108 ret = buf[0]; 109 for (i = 0; i < strlen(buf); i++) 110 buf[i] = buf[i+1]; 111 num--; 112 return ret; 113} 114 115static int menucmd (WINDOW *w) 116{ 117 int ch; 118 119 while (TRUE) { 120 ch = mgetch(w); 121 122 switch (ch) { 123 case '\n': 124 return REQ_EXECUTE; 125 case '\016': 126 case KEYPAD_DOWN_ARROW: 127 return REQ_NEXT_ITEM; 128 case '\020': 129 case KEYPAD_UP_ARROW: 130 return REQ_PREV_ITEM; 131 case '\014': 132 return REQ_REDISPLAY; 133 } 134 135 if (isalpha(ch) || ch == '?') 136 return (ch); 137 138 mbeep(); 139 wrefresh(w); 140 } 141} 142 143static void init_menu (struct menudesc *m) 144{ 145 int max; 146 char **p; 147 int add=4; 148 149 if (m->mopt & NOBOX) 150 add = 2; 151 152 max = strlen(m->title); 153 154 /* Calculate h? */ 155 if (m->h == 0) { 156 m->h = m->numopts + ((m->mopt & NOEXITOPT) ? 0 : 1) 157 - (max ? 0 : 2); 158 } 159 160 161 /* Calculate w? */ 162 if (m->w == 0) { 163 p = m->opts; 164 while (*p) { 165 max = MAX(max,strlen(*p)); 166 p++; 167 } 168 m->w = max; 169 } 170 171 /* Get the windows. */ 172 m->mw = newwin(m->h+add, m->w+add, m->y, m->x); 173 174 if (m->mw == NULL) { 175 endwin(); 176 (void) fprintf (stderr, 177 "Could not create window for window with title " 178 " \"%s\"\n", m->title); 179 exit(1); 180 } 181} 182 183static void post_menu (struct menudesc *m) 184{ 185 int i; 186 int hasbox, cury; 187 int tadd; 188 189 if (m->mopt & NOBOX) { 190 cury = 0; 191 hasbox = 0; 192 } else { 193 cury = 1; 194 hasbox = 1; 195 } 196 197 tadd = strlen(m->title) ? 2 : 0; 198 199 if (tadd) { 200 mvwaddstr(m->mw, cury, cury, m->title); 201 cury += 2; 202 } 203 204 for (i=0; i<m->numopts; i++, cury++) { 205 if (m->cursel == i) { 206 mvwaddstr (m->mw, cury, hasbox, ">"); 207 wstandout(m->mw); 208 } else 209 mvwaddstr (m->mw, cury, hasbox, " "); 210 waddstr (m->mw, m->opts[i]); 211 if (m->cursel == i) 212 wstandend(m->mw); 213 } 214 if (!(m->mopt & NOEXITOPT)) 215 mvwaddstr (m->mw, cury, hasbox, " x: Exit"); 216 217 if (!(m->mopt & NOBOX)) 218 box(m->mw, '*', '*'); 219 220 wmove(m->mw,tadd+hasbox+m->cursel, hasbox); 221} 222 223static void process_help (struct menudesc *m, int num) 224{ 225 char *help = m->helpstr; 226 int lineoff = 0; 227 int curoff = 0; 228 int again; 229 int winin; 230 231 /* Is there help? */ 232 if (!help) { 233 mbeep(); 234 return; 235 } 236 237 /* Display the help information. */ 238 do { 239 if (lineoff < curoff) { 240 help = m->helpstr; 241 curoff = 0; 242 } 243 while (*help && curoff < lineoff) { 244 if (*help == '\n') 245 curoff++; 246 help++; 247 } 248 249 wclear(stdscr); 250 mvwaddstr (stdscr, 0, 0, 251 "Help: exit: q, page up: u <, page down: d >"); 252 mvwaddstr (stdscr, 2, 0, help); 253 wmove (stdscr, 1, 0); 254 wrefresh(stdscr); 255 256 do { 257 winin = mgetch(stdscr); 258 winin = tolower(winin); 259 again = 0; 260 switch (winin) { 261 case '<': 262 case 'u': 263 case KEYPAD_UP_ARROW: 264 if (lineoff) 265 lineoff -= max_lines - 2; 266 break; 267 case '>': 268 case 'd': 269 case KEYPAD_DOWN_ARROW: 270 if (*help) 271 lineoff += max_lines - 2; 272 break; 273 case 'q': 274 break; 275 default: 276 again = 1; 277 } 278 } while (again); 279 } while (winin != 'q'); 280 281 /* Restore current menu */ 282 wclear(stdscr); 283 wrefresh(stdscr); 284 process_item (&num, -2); 285 post_menu (m); 286 wrefresh (m->mw); 287} 288 289static void process_req (struct menudesc *m, int num, int req) 290{ 291 int ch; 292 int lastsel = m->cursel; 293 int hasexit = (m->mopt & NOEXITOPT ? 0 : 1 ); 294 int hasbox = (m->mopt & NOBOX ? 0 : 1); 295 int tadd = strlen(m->title) ? 2 : 0; 296 297 if (req == REQ_EXECUTE) 298 return; 299 else if (req == REQ_NEXT_ITEM) { 300 if (m->cursel < m->numopts + hasexit - 1) 301 m->cursel++; 302 else 303 mbeep(); 304 } else if (req == REQ_PREV_ITEM) { 305 if (m->cursel > 0) 306 m->cursel--; 307 else 308 mbeep(); 309 310 } else if (req == REQ_REDISPLAY) { 311 wclear(stdscr); 312 wrefresh(stdscr); 313 process_item (&num, -2); 314 post_menu (m); 315 wrefresh (m->mw); 316 317 } else if (req == '?') { 318 process_help (m, num); 319 } else { 320 ch = tolower (req); 321 if (ch == 'x' && hasexit) 322 m->cursel = m->numopts; 323 else { 324 ch = ch - 'a'; 325 if (ch < 0 || ch >= m->numopts) 326 mbeep(); 327 else 328 m->cursel = ch; 329 } 330 } 331 if (m->cursel != lastsel) { 332 mvwaddstr (m->mw, lastsel+tadd+hasbox, hasbox, " "); 333 if (lastsel < m->numopts) 334 waddstr (m->mw, m->opts[lastsel]); 335 else 336 waddstr (m->mw, "x: Exit"); 337 mvwaddstr (m->mw, m->cursel+tadd+hasbox, hasbox, ">"); 338 wstandout(m->mw); 339 if (m->cursel < m->numopts) 340 waddstr (m->mw, m->opts[m->cursel]); 341 else 342 waddstr (m->mw, "x: Exit"); 343 wstandend(m->mw); 344 wmove(m->mw,tadd+hasbox+m->cursel, hasbox); 345 wrefresh(m->mw); 346 } 347} 348 349void process_menu (int num) 350{ 351 int sel = 0; 352 int req, done; 353 int last_num; 354 355 struct menudesc *m = &menus[num]; 356 357 done = FALSE; 358 359 /* Initialize? */ 360 if (!__menu_init) { 361 if (initscr() == NULL) { 362 __menu_initerror(); 363 return; 364 } 365 cbreak(); 366 noecho(); 367 max_lines = stdscr->maxy; 368 __menu_init = 1; 369 } 370 if (__m_endwin) { 371 wclear(stdscr); 372 wrefresh(stdscr); 373 __m_endwin = 0; 374 } 375 if (m->mw == NULL) 376 init_menu (m); 377 378 /* Always preselect 0! */ 379 m->cursel = 0; 380 381 while (!done) { 382 last_num = num; 383 if (__m_endwin) { 384 wclear(stdscr); 385 wrefresh(stdscr); 386 __m_endwin = 0; 387 } 388 /* Process the display action */ 389 process_item (&num, -2); 390 post_menu (m); 391 wrefresh (m->mw); 392 393 while ((req = menucmd (m->mw)) != REQ_EXECUTE) 394 process_req (m, num, req); 395 396 sel = m->cursel; 397 wclear (m->mw); 398 wrefresh (m->mw); 399 400 /* Process the items */ 401 if (sel < m->numopts) 402 done = process_item (&num, sel); 403 else 404 done = TRUE; 405 406 /* Reselect m just in case */ 407 if (num != last_num) { 408 m = &menus[num]; 409 /* Initialize? */ 410 if (m->mw == NULL) 411 init_menu (m); 412 process_item (&num, -2); 413 } 414 } 415 416 /* Process the exit action */ 417 process_item (&num, -1); 418} 419