Commit | Line | Data |
---|---|---|
ec215ba5 LM |
1 | /********************************* tui.c ************************************/ |
2 | /* | |
3 | * 'textual user interface' | |
4 | * | |
5 | * Author : P.J. Kunst <kunst@prl.philips.nl> | |
6 | * Date : 1993-02-25 | |
7 | */ | |
8 | ||
9 | #include <ctype.h> | |
10 | #include <curses.h> | |
11 | #include <stdio.h> | |
12 | #include <stdlib.h> | |
13 | #include <string.h> | |
14 | #include <time.h> | |
15 | #include "tui.h" | |
16 | ||
17 | void statusmsg(char *); | |
18 | int waitforkey(void); | |
19 | void rmerror(void); | |
20 | ||
21 | #if defined(__unix) && !defined(__DJGPP__) | |
22 | #include <unistd.h> | |
23 | #endif | |
24 | ||
25 | #ifdef A_COLOR | |
26 | # define TITLECOLOR 1 /* color pair indices */ | |
27 | # define MAINMENUCOLOR (2 | A_BOLD) | |
28 | # define MAINMENUREVCOLOR (3 | A_BOLD | A_REVERSE) | |
29 | # define SUBMENUCOLOR (4 | A_BOLD) | |
30 | # define SUBMENUREVCOLOR (5 | A_BOLD | A_REVERSE) | |
31 | # define BODYCOLOR 6 | |
32 | # define STATUSCOLOR (7 | A_BOLD) | |
33 | # define INPUTBOXCOLOR 8 | |
34 | # define EDITBOXCOLOR (9 | A_BOLD | A_REVERSE) | |
35 | #else | |
36 | # define TITLECOLOR 0 /* color pair indices */ | |
37 | # define MAINMENUCOLOR (A_BOLD) | |
38 | # define MAINMENUREVCOLOR (A_BOLD | A_REVERSE) | |
39 | # define SUBMENUCOLOR (A_BOLD) | |
40 | # define SUBMENUREVCOLOR (A_BOLD | A_REVERSE) | |
41 | # define BODYCOLOR 0 | |
42 | # define STATUSCOLOR (A_BOLD) | |
43 | # define INPUTBOXCOLOR 0 | |
44 | # define EDITBOXCOLOR (A_BOLD | A_REVERSE) | |
45 | #endif | |
46 | ||
47 | ||
48 | #define th 1 /* title window height */ | |
49 | #define mh 1 /* main menu height */ | |
50 | #define sh 2 /* status window height */ | |
51 | #define bh (LINES - th - mh - sh) /* body window height */ | |
52 | #define bw COLS /* body window width */ | |
53 | ||
54 | ||
55 | /******************************* STATIC ************************************/ | |
56 | ||
57 | static WINDOW *wtitl, *wmain, *wbody, *wstat; /* title, menu, body, status win*/ | |
58 | static int nexty, nextx; | |
59 | static int key = ERR, ch = ERR; | |
60 | static bool quit = FALSE; | |
61 | static bool incurses = FALSE; | |
62 | ||
63 | #ifndef PDCURSES | |
64 | static char wordchar(void) | |
65 | { | |
66 | return 0x17; /* ^W */ | |
67 | } | |
68 | #endif | |
69 | ||
70 | static char *padstr(char *s, int length) | |
71 | { | |
72 | static char buf[MAXSTRLEN]; | |
73 | char fmt[10]; | |
74 | ||
75 | sprintf(fmt, (int)strlen(s) > length ? "%%.%ds" : "%%-%ds", length); | |
76 | sprintf(buf, fmt, s); | |
77 | ||
78 | return buf; | |
79 | } | |
80 | ||
81 | static char *prepad(char *s, int length) | |
82 | { | |
83 | int i; | |
84 | char *p = s; | |
85 | ||
86 | if (length > 0) | |
87 | { | |
88 | memmove((void *)(s + length), (const void *)s, strlen(s) + 1); | |
89 | ||
90 | for (i = 0; i < length; i++) | |
91 | *p++ = ' '; | |
92 | } | |
93 | ||
94 | return s; | |
95 | } | |
96 | ||
97 | static void rmline(WINDOW *win, int nr) /* keeps box lines intact */ | |
98 | { | |
99 | mvwaddstr(win, nr, 1, padstr(" ", bw - 2)); | |
100 | wrefresh(win); | |
101 | } | |
102 | ||
103 | static void initcolor(void) | |
104 | { | |
105 | #ifdef A_COLOR | |
106 | if (has_colors()) | |
107 | start_color(); | |
108 | ||
109 | /* foreground, background */ | |
110 | ||
111 | init_pair(TITLECOLOR & ~A_ATTR, COLOR_BLACK, COLOR_BLUE); | |
112 | init_pair(MAINMENUCOLOR & ~A_ATTR, COLOR_WHITE, COLOR_CYAN); | |
113 | init_pair(MAINMENUREVCOLOR & ~A_ATTR, COLOR_WHITE, COLOR_BLACK); | |
114 | init_pair(SUBMENUCOLOR & ~A_ATTR, COLOR_WHITE, COLOR_CYAN); | |
115 | init_pair(SUBMENUREVCOLOR & ~A_ATTR, COLOR_WHITE, COLOR_BLACK); | |
116 | init_pair(BODYCOLOR & ~A_ATTR, COLOR_WHITE, COLOR_BLUE); | |
117 | init_pair(STATUSCOLOR & ~A_ATTR, COLOR_WHITE, COLOR_CYAN); | |
118 | init_pair(INPUTBOXCOLOR & ~A_ATTR, COLOR_BLACK, COLOR_CYAN); | |
119 | init_pair(EDITBOXCOLOR & ~A_ATTR, COLOR_WHITE, COLOR_BLACK); | |
120 | #endif | |
121 | } | |
122 | ||
123 | static void setcolor(WINDOW *win, chtype color) | |
124 | { | |
125 | chtype attr = color & A_ATTR; /* extract Bold, Reverse, Blink bits */ | |
126 | ||
127 | #ifdef A_COLOR | |
128 | attr &= ~A_REVERSE; /* ignore reverse, use colors instead! */ | |
129 | wattrset(win, COLOR_PAIR(color & A_CHARTEXT) | attr); | |
130 | #else | |
131 | attr &= ~A_BOLD; /* ignore bold, gives messy display on HP-UX */ | |
132 | wattrset(win, attr); | |
133 | #endif | |
134 | } | |
135 | ||
136 | static void colorbox(WINDOW *win, chtype color, int hasbox) | |
137 | { | |
138 | int maxy; | |
139 | #ifndef PDCURSES | |
140 | int maxx; | |
141 | #endif | |
142 | chtype attr = color & A_ATTR; /* extract Bold, Reverse, Blink bits */ | |
143 | ||
144 | setcolor(win, color); | |
145 | ||
146 | #ifdef A_COLOR | |
147 | if (has_colors()) | |
148 | wbkgd(win, COLOR_PAIR(color & A_CHARTEXT) | (attr & ~A_REVERSE)); | |
149 | else | |
150 | #endif | |
151 | wbkgd(win, attr); | |
152 | ||
153 | werase(win); | |
154 | ||
155 | #ifdef PDCURSES | |
156 | maxy = getmaxy(win); | |
157 | #else | |
158 | getmaxyx(win, maxy, maxx); | |
159 | #endif | |
160 | if (hasbox && (maxy > 2)) | |
161 | box(win, 0, 0); | |
162 | ||
163 | touchwin(win); | |
164 | wrefresh(win); | |
165 | } | |
166 | ||
167 | static void idle(void) | |
168 | { | |
169 | char buf[MAXSTRLEN]; | |
170 | time_t t; | |
171 | struct tm *tp; | |
172 | ||
173 | if (time (&t) == -1) | |
174 | return; /* time not available */ | |
175 | ||
176 | tp = localtime(&t); | |
177 | sprintf(buf, " %.4d-%.2d-%.2d %.2d:%.2d:%.2d", | |
178 | tp->tm_year + 1900, tp->tm_mon + 1, tp->tm_mday, | |
179 | tp->tm_hour, tp->tm_min, tp->tm_sec); | |
180 | ||
181 | mvwaddstr(wtitl, 0, bw - strlen(buf) - 2, buf); | |
182 | wrefresh(wtitl); | |
183 | } | |
184 | ||
185 | static void menudim(menu *mp, int *lines, int *columns) | |
186 | { | |
187 | int n, l, mmax = 0; | |
188 | ||
189 | for (n = 0; mp->func; n++, mp++) | |
190 | if ((l = strlen(mp->name)) > mmax) mmax = l; | |
191 | ||
192 | *lines = n; | |
193 | *columns = mmax + 2; | |
194 | } | |
195 | ||
196 | static void setmenupos(int y, int x) | |
197 | { | |
198 | nexty = y; | |
199 | nextx = x; | |
200 | } | |
201 | ||
202 | static void getmenupos(int *y, int *x) | |
203 | { | |
204 | *y = nexty; | |
205 | *x = nextx; | |
206 | } | |
207 | ||
208 | static int hotkey(const char *s) | |
209 | { | |
210 | int c0 = *s; /* if no upper case found, return first char */ | |
211 | ||
212 | for (; *s; s++) | |
213 | if (isupper((unsigned char)*s)) | |
214 | break; | |
215 | ||
216 | return *s ? *s : c0; | |
217 | } | |
218 | ||
219 | static void repaintmenu(WINDOW *wmenu, menu *mp) | |
220 | { | |
221 | int i; | |
222 | menu *p = mp; | |
223 | ||
224 | for (i = 0; p->func; i++, p++) | |
225 | mvwaddstr(wmenu, i + 1, 2, p->name); | |
226 | ||
227 | touchwin(wmenu); | |
228 | wrefresh(wmenu); | |
229 | } | |
230 | ||
231 | static void repaintmainmenu(int width, menu *mp) | |
232 | { | |
233 | int i; | |
234 | menu *p = mp; | |
235 | ||
236 | for (i = 0; p->func; i++, p++) | |
237 | mvwaddstr(wmain, 0, i * width, prepad(padstr(p->name, width - 1), 1)); | |
238 | ||
239 | touchwin(wmain); | |
240 | wrefresh(wmain); | |
241 | } | |
242 | ||
243 | void mainhelp(void) | |
244 | { | |
245 | #ifdef ALT_X | |
246 | statusmsg("Use arrow keys and Enter to select (Alt-X to quit)"); | |
247 | #else | |
248 | statusmsg("Use arrow keys and Enter to select"); | |
249 | #endif | |
250 | } | |
251 | ||
252 | void mainmenu(menu *mp) | |
253 | { | |
254 | int nitems, barlen, old = -1, cur = 0, c, cur0; | |
255 | ||
256 | menudim(mp, &nitems, &barlen); | |
257 | repaintmainmenu(barlen, mp); | |
258 | ||
259 | while (!quit) | |
260 | { | |
261 | if (cur != old) | |
262 | { | |
263 | if (old != -1) | |
264 | { | |
265 | mvwaddstr(wmain, 0, old * barlen, | |
266 | prepad(padstr(mp[old].name, barlen - 1), 1)); | |
267 | ||
268 | statusmsg(mp[cur].desc); | |
269 | } | |
270 | else | |
271 | mainhelp(); | |
272 | ||
273 | setcolor(wmain, MAINMENUREVCOLOR); | |
274 | ||
275 | mvwaddstr(wmain, 0, cur * barlen, | |
276 | prepad(padstr(mp[cur].name, barlen - 1), 1)); | |
277 | ||
278 | setcolor(wmain, MAINMENUCOLOR); | |
279 | old = cur; | |
280 | wrefresh(wmain); | |
281 | } | |
282 | ||
283 | switch (c = (key != ERR ? key : waitforkey())) | |
284 | { | |
285 | case KEY_DOWN: | |
286 | case '\n': /* menu item selected */ | |
287 | touchwin(wbody); | |
288 | wrefresh(wbody); | |
289 | rmerror(); | |
290 | setmenupos(th + mh, cur * barlen); | |
291 | curs_set(1); | |
292 | (mp[cur].func)(); /* perform function */ | |
293 | curs_set(0); | |
294 | ||
295 | switch (key) | |
296 | { | |
297 | case KEY_LEFT: | |
298 | cur = (cur + nitems - 1) % nitems; | |
299 | key = '\n'; | |
300 | break; | |
301 | ||
302 | case KEY_RIGHT: | |
303 | cur = (cur + 1) % nitems; | |
304 | key = '\n'; | |
305 | break; | |
306 | ||
307 | default: | |
308 | key = ERR; | |
309 | } | |
310 | ||
311 | repaintmainmenu(barlen, mp); | |
312 | old = -1; | |
313 | break; | |
314 | ||
315 | case KEY_LEFT: | |
316 | cur = (cur + nitems - 1) % nitems; | |
317 | break; | |
318 | ||
319 | case KEY_RIGHT: | |
320 | cur = (cur + 1) % nitems; | |
321 | break; | |
322 | ||
323 | case KEY_ESC: | |
324 | mainhelp(); | |
325 | break; | |
326 | ||
327 | default: | |
328 | cur0 = cur; | |
329 | ||
330 | do | |
331 | { | |
332 | cur = (cur + 1) % nitems; | |
333 | ||
334 | } while ((cur != cur0) && (hotkey(mp[cur].name) != toupper(c))); | |
335 | ||
336 | if (hotkey(mp[cur].name) == toupper(c)) | |
337 | key = '\n'; | |
338 | } | |
339 | ||
340 | } | |
341 | ||
342 | rmerror(); | |
343 | touchwin(wbody); | |
344 | wrefresh(wbody); | |
345 | } | |
346 | ||
347 | static void cleanup(void) /* cleanup curses settings */ | |
348 | { | |
349 | if (incurses) | |
350 | { | |
351 | delwin(wtitl); | |
352 | delwin(wmain); | |
353 | delwin(wbody); | |
354 | delwin(wstat); | |
355 | curs_set(1); | |
356 | endwin(); | |
357 | incurses = FALSE; | |
358 | } | |
359 | } | |
360 | ||
361 | ||
362 | /******************************* EXTERNAL **********************************/ | |
363 | ||
364 | void clsbody(void) | |
365 | { | |
366 | werase(wbody); | |
367 | wmove(wbody, 0, 0); | |
368 | } | |
369 | ||
370 | int bodylen(void) | |
371 | { | |
372 | #ifdef PDCURSES | |
373 | return getmaxy(wbody); | |
374 | #else | |
375 | int maxy, maxx; | |
376 | ||
377 | getmaxyx(wbody, maxy, maxx); | |
378 | return maxy; | |
379 | #endif | |
380 | } | |
381 | ||
382 | WINDOW *bodywin(void) | |
383 | { | |
384 | return wbody; | |
385 | } | |
386 | ||
387 | void rmerror(void) | |
388 | { | |
389 | rmline(wstat, 0); | |
390 | } | |
391 | ||
392 | void rmstatus(void) | |
393 | { | |
394 | rmline(wstat, 1); | |
395 | } | |
396 | ||
397 | void titlemsg(char *msg) | |
398 | { | |
399 | mvwaddstr(wtitl, 0, 2, padstr(msg, bw - 3)); | |
400 | wrefresh(wtitl); | |
401 | } | |
402 | ||
403 | void bodymsg(char *msg) | |
404 | { | |
405 | waddstr(wbody, msg); | |
406 | wrefresh(wbody); | |
407 | } | |
408 | ||
409 | void errormsg(char *msg) | |
410 | { | |
411 | beep(); | |
412 | mvwaddstr(wstat, 0, 2, padstr(msg, bw - 3)); | |
413 | wrefresh(wstat); | |
414 | } | |
415 | ||
416 | void statusmsg(char *msg) | |
417 | { | |
418 | mvwaddstr(wstat, 1, 2, padstr(msg, bw - 3)); | |
419 | wrefresh(wstat); | |
420 | } | |
421 | ||
422 | bool keypressed(void) | |
423 | { | |
424 | ch = wgetch(wbody); | |
425 | ||
426 | return ch != ERR; | |
427 | } | |
428 | ||
429 | int getkey(void) | |
430 | { | |
431 | int c = ch; | |
432 | ||
433 | ch = ERR; | |
434 | #ifdef ALT_X | |
435 | quit = (c == ALT_X); /* PC only ! */ | |
436 | #endif | |
437 | return c; | |
438 | } | |
439 | ||
440 | int waitforkey(void) | |
441 | { | |
442 | do idle(); while (!keypressed()); | |
443 | return getkey(); | |
444 | } | |
445 | ||
446 | void DoExit(void) /* terminate program */ | |
447 | { | |
448 | quit = TRUE; | |
449 | } | |
450 | ||
451 | void domenu(menu *mp) | |
452 | { | |
453 | int y, x, nitems, barlen, mheight, mw, old = -1, cur = 0, cur0; | |
454 | bool stop = FALSE; | |
455 | WINDOW *wmenu; | |
456 | ||
457 | curs_set(0); | |
458 | getmenupos(&y, &x); | |
459 | menudim(mp, &nitems, &barlen); | |
460 | mheight = nitems + 2; | |
461 | mw = barlen + 2; | |
462 | wmenu = newwin(mheight, mw, y, x); | |
463 | colorbox(wmenu, SUBMENUCOLOR, 1); | |
464 | repaintmenu(wmenu, mp); | |
465 | ||
466 | key = ERR; | |
467 | ||
468 | while (!stop && !quit) | |
469 | { | |
470 | if (cur != old) | |
471 | { | |
472 | if (old != -1) | |
473 | mvwaddstr(wmenu, old + 1, 1, | |
474 | prepad(padstr(mp[old].name, barlen - 1), 1)); | |
475 | ||
476 | setcolor(wmenu, SUBMENUREVCOLOR); | |
477 | mvwaddstr(wmenu, cur + 1, 1, | |
478 | prepad(padstr(mp[cur].name, barlen - 1), 1)); | |
479 | ||
480 | setcolor(wmenu, SUBMENUCOLOR); | |
481 | statusmsg(mp[cur].desc); | |
482 | ||
483 | old = cur; | |
484 | wrefresh(wmenu); | |
485 | } | |
486 | ||
487 | switch (key = ((key != ERR) ? key : waitforkey())) | |
488 | { | |
489 | case '\n': /* menu item selected */ | |
490 | touchwin(wbody); | |
491 | wrefresh(wbody); | |
492 | setmenupos(y + 1, x + 1); | |
493 | rmerror(); | |
494 | ||
495 | key = ERR; | |
496 | curs_set(1); | |
497 | (mp[cur].func)(); /* perform function */ | |
498 | curs_set(0); | |
499 | ||
500 | repaintmenu(wmenu, mp); | |
501 | ||
502 | old = -1; | |
503 | break; | |
504 | ||
505 | case KEY_UP: | |
506 | cur = (cur + nitems - 1) % nitems; | |
507 | key = ERR; | |
508 | break; | |
509 | ||
510 | case KEY_DOWN: | |
511 | cur = (cur + 1) % nitems; | |
512 | key = ERR; | |
513 | break; | |
514 | ||
515 | case KEY_ESC: | |
516 | case KEY_LEFT: | |
517 | case KEY_RIGHT: | |
518 | if (key == KEY_ESC) | |
519 | key = ERR; /* return to prev submenu */ | |
520 | ||
521 | stop = TRUE; | |
522 | break; | |
523 | ||
524 | default: | |
525 | cur0 = cur; | |
526 | ||
527 | do | |
528 | { | |
529 | cur = (cur + 1) % nitems; | |
530 | ||
531 | } while ((cur != cur0) && | |
532 | (hotkey(mp[cur].name) != toupper((int)key))); | |
533 | ||
534 | key = (hotkey(mp[cur].name) == toupper((int)key)) ? '\n' : ERR; | |
535 | } | |
536 | ||
537 | } | |
538 | ||
539 | rmerror(); | |
540 | delwin(wmenu); | |
541 | touchwin(wbody); | |
542 | wrefresh(wbody); | |
543 | } | |
544 | ||
545 | void startmenu(menu *mp, char *mtitle, FUNC init) | |
546 | { | |
547 | initscr(); | |
548 | incurses = TRUE; | |
549 | initcolor(); | |
550 | ||
551 | wtitl = subwin(stdscr, th, bw, 0, 0); | |
552 | wmain = subwin(stdscr, mh, bw, th, 0); | |
553 | wbody = subwin(stdscr, bh, bw, th + mh, 0); | |
554 | wstat = subwin(stdscr, sh, bw, th + mh + bh, 0); | |
555 | ||
556 | colorbox(wtitl, TITLECOLOR, 0); | |
557 | colorbox(wmain, MAINMENUCOLOR, 0); | |
558 | colorbox(wbody, BODYCOLOR, 0); | |
559 | colorbox(wstat, STATUSCOLOR, 0); | |
560 | ||
561 | if (mtitle) | |
562 | titlemsg(mtitle); | |
563 | ||
564 | cbreak(); /* direct input (no newline required)... */ | |
565 | noecho(); /* ... without echoing */ | |
566 | curs_set(0); /* hide cursor (if possible) */ | |
567 | nodelay(wbody, TRUE); /* don't wait for input... */ | |
568 | halfdelay(10); /* ...well, no more than a second, anyway */ | |
569 | keypad(wbody, TRUE); /* enable cursor keys */ | |
570 | scrollok(wbody, TRUE); /* enable scrolling in main window */ | |
571 | ||
572 | leaveok(stdscr, TRUE); | |
573 | leaveok(wtitl, TRUE); | |
574 | leaveok(wmain, TRUE); | |
575 | leaveok(wstat, TRUE); | |
576 | ||
577 | if (init) { | |
578 | int nitems, barlen; | |
579 | menudim(mp, &nitems, &barlen); | |
580 | repaintmainmenu(barlen, mp); | |
581 | (*init)(); | |
ec215ba5 | 582 | } |
39699220 | 583 | mainmenu(mp); |
ec215ba5 LM |
584 | |
585 | cleanup(); | |
586 | } | |
587 | ||
588 | static void repainteditbox(WINDOW *win, int x, char *buf) | |
589 | { | |
590 | #ifndef PDCURSES | |
591 | int maxy; | |
592 | #endif | |
593 | int maxx; | |
594 | ||
595 | #ifdef PDCURSES | |
596 | maxx = getmaxx(win); | |
597 | #else | |
598 | getmaxyx(win, maxy, maxx); | |
599 | #endif | |
600 | werase(win); | |
601 | mvwprintw(win, 0, 0, "%s", padstr(buf, maxx)); | |
602 | wmove(win, 0, x); | |
603 | wrefresh(win); | |
604 | } | |
605 | ||
606 | /* | |
607 | ||
608 | weditstr() - edit string | |
609 | ||
610 | Description: | |
611 | The initial value of 'str' with a maximum length of 'field' - 1, | |
612 | which is supplied by the calling routine, is editted. The user's | |
613 | erase (^H), kill (^U) and delete word (^W) chars are interpreted. | |
614 | The PC insert or Tab keys toggle between insert and edit mode. | |
615 | Escape aborts the edit session, leaving 'str' unchanged. | |
616 | Enter, Up or Down Arrow are used to accept the changes to 'str'. | |
617 | NOTE: editstr(), mveditstr(), and mvweditstr() are macros. | |
618 | ||
619 | Return Value: | |
620 | Returns the input terminating character on success (Escape, | |
621 | Enter, Up or Down Arrow) and ERR on error. | |
622 | ||
623 | Errors: | |
624 | It is an error to call this function with a NULL window pointer. | |
625 | The length of the initial 'str' must not exceed 'field' - 1. | |
626 | ||
627 | */ | |
628 | ||
629 | int weditstr(WINDOW *win, char *buf, int field) | |
630 | { | |
631 | char org[MAXSTRLEN], *tp, *bp = buf; | |
632 | bool defdisp = TRUE, stop = FALSE, insert = FALSE; | |
633 | int cury, curx, begy, begx; | |
634 | chtype oldattr; | |
635 | WINDOW *wedit; | |
636 | int c = 0; | |
637 | ||
638 | if ((field >= MAXSTRLEN) || (buf == NULL) || | |
639 | ((int)strlen(buf) > field - 1)) | |
640 | return ERR; | |
641 | ||
642 | strcpy(org, buf); /* save original */ | |
643 | ||
644 | wrefresh(win); | |
645 | getyx(win, cury, curx); | |
646 | getbegyx(win, begy, begx); | |
647 | ||
648 | wedit = subwin(win, 1, field, begy + cury, begx + curx); | |
649 | oldattr = getattrs(wedit); | |
650 | colorbox(wedit, EDITBOXCOLOR, 0); | |
651 | ||
652 | keypad(wedit, TRUE); | |
653 | curs_set(1); | |
654 | ||
655 | while (!stop) | |
656 | { | |
657 | idle(); | |
658 | repainteditbox(wedit, bp - buf, buf); | |
659 | ||
660 | switch (c = wgetch(wedit)) | |
661 | { | |
662 | case ERR: | |
663 | break; | |
664 | ||
665 | case KEY_ESC: | |
666 | strcpy(buf, org); /* restore original */ | |
667 | stop = TRUE; | |
668 | break; | |
669 | ||
670 | case '\n': | |
671 | case KEY_UP: | |
672 | case KEY_DOWN: | |
673 | stop = TRUE; | |
674 | break; | |
675 | ||
676 | case KEY_LEFT: | |
677 | if (bp > buf) | |
678 | bp--; | |
679 | break; | |
680 | ||
681 | case KEY_RIGHT: | |
682 | defdisp = FALSE; | |
683 | if (bp - buf < (int)strlen(buf)) | |
684 | bp++; | |
685 | break; | |
686 | ||
687 | case '\t': /* TAB -- because insert | |
688 | is broken on HPUX */ | |
689 | case KEY_IC: /* enter insert mode */ | |
690 | case KEY_EIC: /* exit insert mode */ | |
691 | defdisp = FALSE; | |
692 | insert = !insert; | |
693 | ||
694 | curs_set(insert ? 2 : 1); | |
695 | break; | |
696 | ||
697 | default: | |
698 | if (c == erasechar()) /* backspace, ^H */ | |
699 | { | |
700 | if (bp > buf) | |
701 | { | |
702 | memmove((void *)(bp - 1), (const void *)bp, strlen(bp) + 1); | |
703 | bp--; | |
704 | } | |
705 | } | |
706 | else if (c == killchar()) /* ^U */ | |
707 | { | |
708 | bp = buf; | |
709 | *bp = '\0'; | |
710 | } | |
711 | else if (c == wordchar()) /* ^W */ | |
712 | { | |
713 | tp = bp; | |
714 | ||
715 | while ((bp > buf) && (*(bp - 1) == ' ')) | |
716 | bp--; | |
717 | while ((bp > buf) && (*(bp - 1) != ' ')) | |
718 | bp--; | |
719 | ||
720 | memmove((void *)bp, (const void *)tp, strlen(tp) + 1); | |
721 | } | |
722 | else if (isprint(c)) | |
723 | { | |
724 | if (defdisp) | |
725 | { | |
726 | bp = buf; | |
727 | *bp = '\0'; | |
728 | defdisp = FALSE; | |
729 | } | |
730 | ||
731 | if (insert) | |
732 | { | |
733 | if ((int)strlen(buf) < field - 1) | |
734 | { | |
735 | memmove((void *)(bp + 1), (const void *)bp, | |
736 | strlen(bp) + 1); | |
737 | ||
738 | *bp++ = c; | |
739 | } | |
740 | } | |
741 | else if (bp - buf < field - 1) | |
742 | { | |
743 | /* append new string terminator */ | |
744 | ||
745 | if (!*bp) | |
746 | bp[1] = '\0'; | |
747 | ||
748 | *bp++ = c; | |
749 | } | |
750 | } | |
751 | } | |
752 | } | |
753 | ||
754 | curs_set(0); | |
755 | ||
756 | wattrset(wedit, oldattr); | |
757 | repainteditbox(wedit, bp - buf, buf); | |
758 | delwin(wedit); | |
759 | ||
760 | return c; | |
761 | } | |
762 | ||
763 | WINDOW *winputbox(WINDOW *win, int nlines, int ncols) | |
764 | { | |
765 | WINDOW *winp; | |
766 | int cury, curx, begy, begx; | |
767 | ||
768 | getyx(win, cury, curx); | |
769 | getbegyx(win, begy, begx); | |
770 | ||
771 | winp = newwin(nlines, ncols, begy + cury, begx + curx); | |
772 | colorbox(winp, INPUTBOXCOLOR, 1); | |
773 | ||
774 | return winp; | |
775 | } | |
776 | ||
777 | int getstrings(char *desc[], char *buf[], int field) | |
778 | { | |
779 | WINDOW *winput; | |
780 | int oldy, oldx, maxy, maxx, nlines, ncols, i, n, l, mmax = 0; | |
781 | int c = 0; | |
782 | bool stop = FALSE; | |
783 | ||
784 | for (n = 0; desc[n]; n++) | |
785 | if ((l = strlen(desc[n])) > mmax) | |
786 | mmax = l; | |
787 | ||
788 | nlines = n + 2; ncols = mmax + field + 4; | |
789 | getyx(wbody, oldy, oldx); | |
790 | getmaxyx(wbody, maxy, maxx); | |
791 | ||
792 | winput = mvwinputbox(wbody, (maxy - nlines) / 2, (maxx - ncols) / 2, | |
793 | nlines, ncols); | |
794 | ||
795 | for (i = 0; i < n; i++) | |
796 | mvwprintw(winput, i + 1, 2, "%s", desc[i]); | |
797 | ||
798 | i = 0; | |
799 | ||
800 | while (!stop) | |
801 | { | |
802 | switch (c = mvweditstr(winput, i+1, mmax+3, buf[i], field)) | |
803 | { | |
804 | case KEY_ESC: | |
805 | stop = TRUE; | |
806 | break; | |
807 | ||
808 | case KEY_UP: | |
809 | i = (i + n - 1) % n; | |
810 | break; | |
811 | ||
812 | case '\n': | |
813 | case '\t': | |
814 | case KEY_DOWN: | |
815 | if (++i == n) | |
816 | stop = TRUE; /* all passed? */ | |
817 | } | |
818 | } | |
819 | ||
820 | delwin(winput); | |
821 | touchwin(wbody); | |
822 | wmove(wbody, oldy, oldx); | |
823 | wrefresh(wbody); | |
824 | ||
825 | return c; | |
826 | } | |
97efd1ff LM |
827 | |
828 | /* vim: set ts=4 sw=4 et: */ |