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 | |
5b21f9be | 140 | int __attribute__((unused)) maxx; |
ec215ba5 LM |
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: | |
4424d941 | 286 | case 'k': |
ec215ba5 LM |
287 | case '\n': /* menu item selected */ |
288 | touchwin(wbody); | |
289 | wrefresh(wbody); | |
290 | rmerror(); | |
291 | setmenupos(th + mh, cur * barlen); | |
292 | curs_set(1); | |
293 | (mp[cur].func)(); /* perform function */ | |
294 | curs_set(0); | |
295 | ||
296 | switch (key) | |
297 | { | |
298 | case KEY_LEFT: | |
4424d941 | 299 | case 'j': |
ec215ba5 LM |
300 | cur = (cur + nitems - 1) % nitems; |
301 | key = '\n'; | |
302 | break; | |
303 | ||
304 | case KEY_RIGHT: | |
4424d941 | 305 | case 'l': |
ec215ba5 LM |
306 | cur = (cur + 1) % nitems; |
307 | key = '\n'; | |
308 | break; | |
309 | ||
310 | default: | |
311 | key = ERR; | |
312 | } | |
313 | ||
314 | repaintmainmenu(barlen, mp); | |
315 | old = -1; | |
316 | break; | |
317 | ||
318 | case KEY_LEFT: | |
4424d941 | 319 | case 'j': |
ec215ba5 LM |
320 | cur = (cur + nitems - 1) % nitems; |
321 | break; | |
322 | ||
323 | case KEY_RIGHT: | |
4424d941 | 324 | case 'l': |
ec215ba5 LM |
325 | cur = (cur + 1) % nitems; |
326 | break; | |
327 | ||
328 | case KEY_ESC: | |
329 | mainhelp(); | |
330 | break; | |
331 | ||
332 | default: | |
333 | cur0 = cur; | |
334 | ||
335 | do | |
336 | { | |
337 | cur = (cur + 1) % nitems; | |
338 | ||
339 | } while ((cur != cur0) && (hotkey(mp[cur].name) != toupper(c))); | |
340 | ||
341 | if (hotkey(mp[cur].name) == toupper(c)) | |
342 | key = '\n'; | |
343 | } | |
344 | ||
345 | } | |
346 | ||
347 | rmerror(); | |
348 | touchwin(wbody); | |
349 | wrefresh(wbody); | |
350 | } | |
351 | ||
53cd5b25 | 352 | void cleanup(void) /* cleanup curses settings */ |
ec215ba5 LM |
353 | { |
354 | if (incurses) | |
355 | { | |
356 | delwin(wtitl); | |
357 | delwin(wmain); | |
358 | delwin(wbody); | |
359 | delwin(wstat); | |
360 | curs_set(1); | |
361 | endwin(); | |
362 | incurses = FALSE; | |
363 | } | |
364 | } | |
365 | ||
366 | ||
367 | /******************************* EXTERNAL **********************************/ | |
368 | ||
369 | void clsbody(void) | |
370 | { | |
371 | werase(wbody); | |
372 | wmove(wbody, 0, 0); | |
373 | } | |
374 | ||
375 | int bodylen(void) | |
376 | { | |
377 | #ifdef PDCURSES | |
378 | return getmaxy(wbody); | |
379 | #else | |
5b21f9be | 380 | int maxy, __attribute__((unused)) maxx; |
ec215ba5 LM |
381 | |
382 | getmaxyx(wbody, maxy, maxx); | |
383 | return maxy; | |
384 | #endif | |
385 | } | |
386 | ||
387 | WINDOW *bodywin(void) | |
388 | { | |
389 | return wbody; | |
390 | } | |
391 | ||
392 | void rmerror(void) | |
393 | { | |
394 | rmline(wstat, 0); | |
395 | } | |
396 | ||
397 | void rmstatus(void) | |
398 | { | |
399 | rmline(wstat, 1); | |
400 | } | |
401 | ||
402 | void titlemsg(char *msg) | |
403 | { | |
404 | mvwaddstr(wtitl, 0, 2, padstr(msg, bw - 3)); | |
405 | wrefresh(wtitl); | |
406 | } | |
407 | ||
408 | void bodymsg(char *msg) | |
409 | { | |
410 | waddstr(wbody, msg); | |
411 | wrefresh(wbody); | |
412 | } | |
413 | ||
414 | void errormsg(char *msg) | |
415 | { | |
416 | beep(); | |
417 | mvwaddstr(wstat, 0, 2, padstr(msg, bw - 3)); | |
418 | wrefresh(wstat); | |
419 | } | |
420 | ||
421 | void statusmsg(char *msg) | |
422 | { | |
423 | mvwaddstr(wstat, 1, 2, padstr(msg, bw - 3)); | |
424 | wrefresh(wstat); | |
425 | } | |
426 | ||
427 | bool keypressed(void) | |
428 | { | |
429 | ch = wgetch(wbody); | |
430 | ||
431 | return ch != ERR; | |
432 | } | |
433 | ||
434 | int getkey(void) | |
435 | { | |
436 | int c = ch; | |
437 | ||
438 | ch = ERR; | |
439 | #ifdef ALT_X | |
440 | quit = (c == ALT_X); /* PC only ! */ | |
441 | #endif | |
442 | return c; | |
443 | } | |
444 | ||
445 | int waitforkey(void) | |
446 | { | |
447 | do idle(); while (!keypressed()); | |
448 | return getkey(); | |
449 | } | |
450 | ||
451 | void DoExit(void) /* terminate program */ | |
452 | { | |
453 | quit = TRUE; | |
454 | } | |
455 | ||
456 | void domenu(menu *mp) | |
457 | { | |
458 | int y, x, nitems, barlen, mheight, mw, old = -1, cur = 0, cur0; | |
459 | bool stop = FALSE; | |
460 | WINDOW *wmenu; | |
461 | ||
462 | curs_set(0); | |
463 | getmenupos(&y, &x); | |
464 | menudim(mp, &nitems, &barlen); | |
465 | mheight = nitems + 2; | |
466 | mw = barlen + 2; | |
467 | wmenu = newwin(mheight, mw, y, x); | |
468 | colorbox(wmenu, SUBMENUCOLOR, 1); | |
469 | repaintmenu(wmenu, mp); | |
470 | ||
471 | key = ERR; | |
472 | ||
473 | while (!stop && !quit) | |
474 | { | |
475 | if (cur != old) | |
476 | { | |
477 | if (old != -1) | |
478 | mvwaddstr(wmenu, old + 1, 1, | |
479 | prepad(padstr(mp[old].name, barlen - 1), 1)); | |
480 | ||
481 | setcolor(wmenu, SUBMENUREVCOLOR); | |
482 | mvwaddstr(wmenu, cur + 1, 1, | |
483 | prepad(padstr(mp[cur].name, barlen - 1), 1)); | |
484 | ||
485 | setcolor(wmenu, SUBMENUCOLOR); | |
486 | statusmsg(mp[cur].desc); | |
487 | ||
488 | old = cur; | |
489 | wrefresh(wmenu); | |
490 | } | |
491 | ||
492 | switch (key = ((key != ERR) ? key : waitforkey())) | |
493 | { | |
494 | case '\n': /* menu item selected */ | |
495 | touchwin(wbody); | |
496 | wrefresh(wbody); | |
497 | setmenupos(y + 1, x + 1); | |
498 | rmerror(); | |
499 | ||
500 | key = ERR; | |
501 | curs_set(1); | |
502 | (mp[cur].func)(); /* perform function */ | |
503 | curs_set(0); | |
504 | ||
505 | repaintmenu(wmenu, mp); | |
506 | ||
507 | old = -1; | |
508 | break; | |
509 | ||
510 | case KEY_UP: | |
c2074f6c | 511 | case 'i': |
ec215ba5 LM |
512 | cur = (cur + nitems - 1) % nitems; |
513 | key = ERR; | |
514 | break; | |
515 | ||
516 | case KEY_DOWN: | |
c2074f6c | 517 | case 'k': |
ec215ba5 LM |
518 | cur = (cur + 1) % nitems; |
519 | key = ERR; | |
520 | break; | |
521 | ||
522 | case KEY_ESC: | |
4424d941 | 523 | case ':': |
ec215ba5 | 524 | case KEY_LEFT: |
4424d941 | 525 | case 'j': |
ec215ba5 | 526 | case KEY_RIGHT: |
4424d941 LM |
527 | case 'l': |
528 | if ((key == KEY_ESC) || (key == ':')) | |
ec215ba5 LM |
529 | key = ERR; /* return to prev submenu */ |
530 | ||
531 | stop = TRUE; | |
532 | break; | |
533 | ||
534 | default: | |
535 | cur0 = cur; | |
536 | ||
537 | do | |
538 | { | |
539 | cur = (cur + 1) % nitems; | |
540 | ||
541 | } while ((cur != cur0) && | |
542 | (hotkey(mp[cur].name) != toupper((int)key))); | |
543 | ||
544 | key = (hotkey(mp[cur].name) == toupper((int)key)) ? '\n' : ERR; | |
545 | } | |
546 | ||
547 | } | |
548 | ||
549 | rmerror(); | |
550 | delwin(wmenu); | |
551 | touchwin(wbody); | |
552 | wrefresh(wbody); | |
553 | } | |
554 | ||
555 | void startmenu(menu *mp, char *mtitle, FUNC init) | |
556 | { | |
557 | initscr(); | |
558 | incurses = TRUE; | |
559 | initcolor(); | |
560 | ||
561 | wtitl = subwin(stdscr, th, bw, 0, 0); | |
562 | wmain = subwin(stdscr, mh, bw, th, 0); | |
563 | wbody = subwin(stdscr, bh, bw, th + mh, 0); | |
564 | wstat = subwin(stdscr, sh, bw, th + mh + bh, 0); | |
565 | ||
566 | colorbox(wtitl, TITLECOLOR, 0); | |
567 | colorbox(wmain, MAINMENUCOLOR, 0); | |
568 | colorbox(wbody, BODYCOLOR, 0); | |
569 | colorbox(wstat, STATUSCOLOR, 0); | |
570 | ||
571 | if (mtitle) | |
572 | titlemsg(mtitle); | |
573 | ||
574 | cbreak(); /* direct input (no newline required)... */ | |
575 | noecho(); /* ... without echoing */ | |
576 | curs_set(0); /* hide cursor (if possible) */ | |
577 | nodelay(wbody, TRUE); /* don't wait for input... */ | |
578 | halfdelay(10); /* ...well, no more than a second, anyway */ | |
579 | keypad(wbody, TRUE); /* enable cursor keys */ | |
580 | scrollok(wbody, TRUE); /* enable scrolling in main window */ | |
581 | ||
582 | leaveok(stdscr, TRUE); | |
583 | leaveok(wtitl, TRUE); | |
584 | leaveok(wmain, TRUE); | |
585 | leaveok(wstat, TRUE); | |
586 | ||
587 | if (init) { | |
588 | int nitems, barlen; | |
589 | menudim(mp, &nitems, &barlen); | |
590 | repaintmainmenu(barlen, mp); | |
591 | (*init)(); | |
ec215ba5 | 592 | } |
39699220 | 593 | mainmenu(mp); |
ec215ba5 LM |
594 | |
595 | cleanup(); | |
596 | } | |
597 | ||
598 | static void repainteditbox(WINDOW *win, int x, char *buf) | |
599 | { | |
600 | #ifndef PDCURSES | |
5b21f9be | 601 | int __attribute__((unused)) maxy; |
ec215ba5 LM |
602 | #endif |
603 | int maxx; | |
604 | ||
605 | #ifdef PDCURSES | |
606 | maxx = getmaxx(win); | |
607 | #else | |
608 | getmaxyx(win, maxy, maxx); | |
609 | #endif | |
610 | werase(win); | |
611 | mvwprintw(win, 0, 0, "%s", padstr(buf, maxx)); | |
612 | wmove(win, 0, x); | |
613 | wrefresh(win); | |
614 | } | |
615 | ||
616 | /* | |
617 | ||
618 | weditstr() - edit string | |
619 | ||
620 | Description: | |
621 | The initial value of 'str' with a maximum length of 'field' - 1, | |
622 | which is supplied by the calling routine, is editted. The user's | |
623 | erase (^H), kill (^U) and delete word (^W) chars are interpreted. | |
624 | The PC insert or Tab keys toggle between insert and edit mode. | |
625 | Escape aborts the edit session, leaving 'str' unchanged. | |
626 | Enter, Up or Down Arrow are used to accept the changes to 'str'. | |
627 | NOTE: editstr(), mveditstr(), and mvweditstr() are macros. | |
628 | ||
629 | Return Value: | |
630 | Returns the input terminating character on success (Escape, | |
631 | Enter, Up or Down Arrow) and ERR on error. | |
632 | ||
633 | Errors: | |
634 | It is an error to call this function with a NULL window pointer. | |
635 | The length of the initial 'str' must not exceed 'field' - 1. | |
636 | ||
637 | */ | |
638 | ||
639 | int weditstr(WINDOW *win, char *buf, int field) | |
640 | { | |
641 | char org[MAXSTRLEN], *tp, *bp = buf; | |
642 | bool defdisp = TRUE, stop = FALSE, insert = FALSE; | |
643 | int cury, curx, begy, begx; | |
644 | chtype oldattr; | |
645 | WINDOW *wedit; | |
646 | int c = 0; | |
647 | ||
648 | if ((field >= MAXSTRLEN) || (buf == NULL) || | |
649 | ((int)strlen(buf) > field - 1)) | |
650 | return ERR; | |
651 | ||
652 | strcpy(org, buf); /* save original */ | |
653 | ||
654 | wrefresh(win); | |
655 | getyx(win, cury, curx); | |
656 | getbegyx(win, begy, begx); | |
657 | ||
658 | wedit = subwin(win, 1, field, begy + cury, begx + curx); | |
659 | oldattr = getattrs(wedit); | |
660 | colorbox(wedit, EDITBOXCOLOR, 0); | |
661 | ||
662 | keypad(wedit, TRUE); | |
663 | curs_set(1); | |
664 | ||
cbac1b10 | 665 | int mode = 0; |
ec215ba5 LM |
666 | while (!stop) |
667 | { | |
668 | idle(); | |
669 | repainteditbox(wedit, bp - buf, buf); | |
670 | ||
cbac1b10 LM |
671 | c = wgetch(wedit); |
672 | if (mode) { | |
ca818a82 LM |
673 | if (mode == 1) { |
674 | mode = (c == KEY_ESC) ? 2 : 3; | |
675 | } | |
676 | ||
cbac1b10 LM |
677 | switch (c) { |
678 | case 'i': | |
679 | c = KEY_UP; | |
680 | break; | |
681 | case 'j': | |
682 | c = KEY_LEFT; | |
683 | break; | |
684 | case 'k': | |
685 | c = KEY_DOWN; | |
686 | break; | |
687 | case 'l': | |
688 | c = KEY_RIGHT; | |
689 | break; | |
cbac1b10 | 690 | case KEY_ESC: |
ca818a82 LM |
691 | if (mode == 3) { |
692 | c = ERR; | |
693 | mode = 0; | |
694 | } | |
695 | break; | |
696 | case '\n': | |
cbac1b10 LM |
697 | mode = 0; |
698 | /* fallthrough */ | |
699 | default: | |
700 | c = ERR; | |
701 | } | |
702 | } | |
703 | switch (c) { | |
ec215ba5 LM |
704 | case ERR: |
705 | break; | |
706 | ||
707 | case KEY_ESC: | |
cbac1b10 LM |
708 | if (!mode) { |
709 | mode = 1; | |
710 | break; | |
711 | } | |
ec215ba5 LM |
712 | strcpy(buf, org); /* restore original */ |
713 | stop = TRUE; | |
714 | break; | |
715 | ||
716 | case '\n': | |
717 | case KEY_UP: | |
718 | case KEY_DOWN: | |
719 | stop = TRUE; | |
720 | break; | |
721 | ||
722 | case KEY_LEFT: | |
723 | if (bp > buf) | |
724 | bp--; | |
725 | break; | |
726 | ||
727 | case KEY_RIGHT: | |
728 | defdisp = FALSE; | |
729 | if (bp - buf < (int)strlen(buf)) | |
730 | bp++; | |
731 | break; | |
732 | ||
733 | case '\t': /* TAB -- because insert | |
734 | is broken on HPUX */ | |
735 | case KEY_IC: /* enter insert mode */ | |
736 | case KEY_EIC: /* exit insert mode */ | |
737 | defdisp = FALSE; | |
738 | insert = !insert; | |
739 | ||
740 | curs_set(insert ? 2 : 1); | |
741 | break; | |
742 | ||
743 | default: | |
744 | if (c == erasechar()) /* backspace, ^H */ | |
745 | { | |
746 | if (bp > buf) | |
747 | { | |
748 | memmove((void *)(bp - 1), (const void *)bp, strlen(bp) + 1); | |
749 | bp--; | |
750 | } | |
751 | } | |
752 | else if (c == killchar()) /* ^U */ | |
753 | { | |
754 | bp = buf; | |
755 | *bp = '\0'; | |
756 | } | |
757 | else if (c == wordchar()) /* ^W */ | |
758 | { | |
759 | tp = bp; | |
760 | ||
761 | while ((bp > buf) && (*(bp - 1) == ' ')) | |
762 | bp--; | |
763 | while ((bp > buf) && (*(bp - 1) != ' ')) | |
764 | bp--; | |
765 | ||
766 | memmove((void *)bp, (const void *)tp, strlen(tp) + 1); | |
767 | } | |
768 | else if (isprint(c)) | |
769 | { | |
770 | if (defdisp) | |
771 | { | |
772 | bp = buf; | |
773 | *bp = '\0'; | |
774 | defdisp = FALSE; | |
775 | } | |
776 | ||
777 | if (insert) | |
778 | { | |
779 | if ((int)strlen(buf) < field - 1) | |
780 | { | |
781 | memmove((void *)(bp + 1), (const void *)bp, | |
782 | strlen(bp) + 1); | |
783 | ||
784 | *bp++ = c; | |
785 | } | |
786 | } | |
787 | else if (bp - buf < field - 1) | |
788 | { | |
789 | /* append new string terminator */ | |
790 | ||
791 | if (!*bp) | |
792 | bp[1] = '\0'; | |
793 | ||
794 | *bp++ = c; | |
795 | } | |
796 | } | |
797 | } | |
798 | } | |
799 | ||
800 | curs_set(0); | |
801 | ||
802 | wattrset(wedit, oldattr); | |
803 | repainteditbox(wedit, bp - buf, buf); | |
804 | delwin(wedit); | |
805 | ||
806 | return c; | |
807 | } | |
808 | ||
809 | WINDOW *winputbox(WINDOW *win, int nlines, int ncols) | |
810 | { | |
811 | WINDOW *winp; | |
812 | int cury, curx, begy, begx; | |
813 | ||
814 | getyx(win, cury, curx); | |
815 | getbegyx(win, begy, begx); | |
816 | ||
817 | winp = newwin(nlines, ncols, begy + cury, begx + curx); | |
818 | colorbox(winp, INPUTBOXCOLOR, 1); | |
819 | ||
820 | return winp; | |
821 | } | |
822 | ||
823 | int getstrings(char *desc[], char *buf[], int field) | |
824 | { | |
825 | WINDOW *winput; | |
826 | int oldy, oldx, maxy, maxx, nlines, ncols, i, n, l, mmax = 0; | |
827 | int c = 0; | |
828 | bool stop = FALSE; | |
829 | ||
830 | for (n = 0; desc[n]; n++) | |
831 | if ((l = strlen(desc[n])) > mmax) | |
832 | mmax = l; | |
833 | ||
834 | nlines = n + 2; ncols = mmax + field + 4; | |
835 | getyx(wbody, oldy, oldx); | |
836 | getmaxyx(wbody, maxy, maxx); | |
837 | ||
838 | winput = mvwinputbox(wbody, (maxy - nlines) / 2, (maxx - ncols) / 2, | |
839 | nlines, ncols); | |
840 | ||
841 | for (i = 0; i < n; i++) | |
842 | mvwprintw(winput, i + 1, 2, "%s", desc[i]); | |
843 | ||
844 | i = 0; | |
845 | ||
846 | while (!stop) | |
847 | { | |
848 | switch (c = mvweditstr(winput, i+1, mmax+3, buf[i], field)) | |
849 | { | |
850 | case KEY_ESC: | |
851 | stop = TRUE; | |
852 | break; | |
853 | ||
854 | case KEY_UP: | |
855 | i = (i + n - 1) % n; | |
856 | break; | |
857 | ||
858 | case '\n': | |
859 | case '\t': | |
860 | case KEY_DOWN: | |
861 | if (++i == n) | |
862 | stop = TRUE; /* all passed? */ | |
863 | } | |
864 | } | |
865 | ||
866 | delwin(winput); | |
867 | touchwin(wbody); | |
868 | wmove(wbody, oldy, oldx); | |
869 | wrefresh(wbody); | |
870 | ||
871 | return c; | |
872 | } | |
97efd1ff LM |
873 | |
874 | /* vim: set ts=4 sw=4 et: */ |