menu_sys.def revision 1.2
1/* $NetBSD: menu_sys.def,v 1.2 1997/11/09 20:59:15 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 48#define KEYPAD_DOWN_ARROW 256 49#define KEYPAD_UP_ARROW 257 50 51#define MAX(x,y) ((x)>(y)?(x):(y)) 52 53/* Initialization state. */ 54static int __menu_init = 0; 55int __m_endwin = 0; 56 57/* prototypes for in here! */ 58 59static void init_menu (struct menudesc *m); 60static void post_menu (struct menudesc *m); 61static void process_req (struct menudesc *m, int req); 62static void mbeep (void); 63static int menucmd (WINDOW *w); 64 65#ifndef NULL 66#define NULL (void *)0 67#endif 68 69/* menu system processing routines */ 70 71static void mbeep (void) 72{ 73 fprintf (stderr,"\a"); 74} 75 76static int mgetch(WINDOW *w) 77{ 78 static char buf[20]; 79 static int num = 0; 80 81 int i, ret; 82 83 for (i=0; i< strlen(KD); i++) { 84 if (i >= num) 85 buf[num++] = wgetch(w); 86 if (buf[i] != KD[i]) 87 break; 88 } 89 if (i == strlen(KD)) { 90 num = 0; 91 return KEYPAD_DOWN_ARROW; 92 } 93 94 for (i=0; i< strlen(KU); i++) { 95 if (i >= num) 96 buf[num++] = wgetch(w); 97 if (buf[i] != KU[i]) 98 break; 99 } 100 if (i == strlen(KU)) { 101 num = 0; 102 return KEYPAD_UP_ARROW; 103 } 104 105 ret = buf[0]; 106 for (i = 0; i < strlen(buf); i++) 107 buf[i] = buf[i+1]; 108 num--; 109 return ret; 110} 111 112static int menucmd (WINDOW *w) 113{ 114 int ch; 115 116 while (TRUE) { 117 ch = mgetch(w); 118 119 switch (ch) { 120 case '\n': 121 return REQ_EXECUTE; 122 case '\016': 123 case KEYPAD_DOWN_ARROW: 124 return REQ_NEXT_ITEM; 125 case '\020': 126 case KEYPAD_UP_ARROW: 127 return REQ_PREV_ITEM; 128 } 129 130 if (isalpha(ch)) 131 return (ch); 132 133 mbeep(); 134 wrefresh(w); 135 } 136} 137 138static void init_menu (struct menudesc *m) 139{ 140 int max; 141 char **p; 142 int add=4; 143 144 if (m->mopt & NOBOX) 145 add = 2; 146 147 max = strlen(m->title); 148 149 /* Calculate h? */ 150 if (m->h == 0) { 151 m->h = m->numopts + ((m->mopt & NOEXITOPT) ? 0 : 1) 152 - (max ? 0 : 2); 153 } 154 155 156 /* Calculate w? */ 157 if (m->w == 0) { 158 p = m->opts; 159 while (*p) { 160 max = MAX(max,strlen(*p)); 161 p++; 162 } 163 m->w = max; 164 } 165 166 /* Get the windows. */ 167 m->mw = newwin(m->h+add, m->w+add, m->y, m->x); 168 169 if (m->mw == NULL) { 170 endwin(); 171 (void) fprintf (stderr, 172 "Could not create window for window with title " 173 " \"%s\"\n", m->title); 174 exit(1); 175 } 176} 177 178static void post_menu (struct menudesc *m) 179{ 180 int i; 181 int hasbox, cury; 182 int tadd; 183 184 if (m->mopt & NOBOX) { 185 cury = 0; 186 hasbox = 0; 187 } else { 188 cury = 1; 189 hasbox = 1; 190 } 191 192 tadd = strlen(m->title) ? 2 : 0; 193 194 if (tadd) { 195 mvwaddstr(m->mw, cury, cury, m->title); 196 cury += 2; 197 } 198 199 for (i=0; i<m->numopts; i++, cury++) { 200 if (m->cursel == i) { 201 mvwaddstr (m->mw, cury, hasbox, ">"); 202 wstandout(m->mw); 203 } else 204 mvwaddstr (m->mw, cury, hasbox, " "); 205 waddstr (m->mw, m->opts[i]); 206 if (m->cursel == i) 207 wstandend(m->mw); 208 } 209 if (!(m->mopt & NOEXITOPT)) 210 mvwaddstr (m->mw, cury, hasbox, " x: Exit"); 211 212 if (!(m->mopt & NOBOX)) 213 box(m->mw, '*', '*'); 214 215 wmove(m->mw,tadd+hasbox+m->cursel, hasbox); 216} 217 218static void process_req (struct menudesc *m, int req) 219{ 220 int ch; 221 int lastsel = m->cursel; 222 int hasexit = (m->mopt & NOEXITOPT ? 0 : 1 ); 223 int hasbox = (m->mopt & NOBOX ? 0 : 1); 224 int tadd = strlen(m->title) ? 2 : 0; 225 226 if (req == REQ_EXECUTE) 227 return; 228 else if (req == REQ_NEXT_ITEM) { 229 if (m->cursel < m->numopts + hasexit - 1) 230 m->cursel++; 231 else 232 mbeep(); 233 } else if (req == REQ_PREV_ITEM) { 234 if (m->cursel > 0) 235 m->cursel--; 236 else 237 mbeep(); 238 } else { 239 ch = tolower (req); 240 if (ch == 'x' && hasexit) 241 m->cursel = m->numopts; 242 else { 243 ch = ch - 'a'; 244 if (ch < 0 || ch >= m->numopts) 245 mbeep(); 246 else 247 m->cursel = ch; 248 } 249 } 250 if (m->cursel != lastsel) { 251 mvwaddstr (m->mw, lastsel+tadd+hasbox, hasbox, " "); 252 if (lastsel < m->numopts) 253 waddstr (m->mw, m->opts[lastsel]); 254 else 255 waddstr (m->mw, "x: Exit"); 256 mvwaddstr (m->mw, m->cursel+tadd+hasbox, hasbox, ">"); 257 wstandout(m->mw); 258 if (m->cursel < m->numopts) 259 waddstr (m->mw, m->opts[m->cursel]); 260 else 261 waddstr (m->mw, "x: Exit"); 262 wstandend(m->mw); 263 wmove(m->mw,tadd+hasbox+m->cursel, hasbox); 264 wrefresh(m->mw); 265 } 266} 267 268void process_menu (int num) 269{ 270 int sel = 0; 271 int req, done; 272 int last_num; 273 274 struct menudesc *m = &menus[num]; 275 276 done = FALSE; 277 278 /* Initialize? */ 279 if (!__menu_init) { 280 if (initscr() == NULL) { 281 __menu_initerror(); 282 return; 283 } 284 cbreak(); 285 noecho(); 286 __menu_init = 1; 287 } 288 if (__m_endwin) { 289 wclear(stdscr); 290 wrefresh(stdscr); 291 __m_endwin = 0; 292 } 293 if (m->mw == NULL) 294 init_menu (m); 295 296 /* Always preselect 0! */ 297 m->cursel = 0; 298 299 while (!done) { 300 last_num = num; 301 if (__m_endwin) { 302 wclear(stdscr); 303 wrefresh(stdscr); 304 __m_endwin = 0; 305 } 306 /* Process the display action */ 307 process_item (&num, -2); 308 post_menu (m); 309 wrefresh (m->mw); 310 311 while ((req = menucmd (m->mw)) != REQ_EXECUTE) 312 process_req (m, req); 313 314 sel = m->cursel; 315 wclear (m->mw); 316 wrefresh (m->mw); 317 318 /* Process the items */ 319 if (sel < m->numopts) 320 done = process_item (&num, sel); 321 else 322 done = TRUE; 323 324 /* Reselect m just in case */ 325 if (num != last_num) { 326 m = &menus[num]; 327 /* Initialize? */ 328 if (m->mw == NULL) 329 init_menu (m); 330 process_item (&num, -2); 331 } 332 } 333 334 /* Process the exit action */ 335 process_item (&num, -1); 336} 337