add more test (3)
[cmore.git] / tui.c
CommitLineData
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
17void statusmsg(char *);
18int waitforkey(void);
19void 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
57static WINDOW *wtitl, *wmain, *wbody, *wstat; /* title, menu, body, status win*/
58static int nexty, nextx;
59static int key = ERR, ch = ERR;
60static bool quit = FALSE;
61static bool incurses = FALSE;
62
63#ifndef PDCURSES
64static char wordchar(void)
65{
66 return 0x17; /* ^W */
67}
68#endif
69
70static 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
81static 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
97static void rmline(WINDOW *win, int nr) /* keeps box lines intact */
98{
99 mvwaddstr(win, nr, 1, padstr(" ", bw - 2));
100 wrefresh(win);
101}
102
103static 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
123static 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
136static 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
167static 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
185static 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
196static void setmenupos(int y, int x)
197{
198 nexty = y;
199 nextx = x;
200}
201
202static void getmenupos(int *y, int *x)
203{
204 *y = nexty;
205 *x = nextx;
206}
207
208static 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
219static 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
231static 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
243void 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
252void 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 352void 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
369void clsbody(void)
370{
371 werase(wbody);
372 wmove(wbody, 0, 0);
373}
374
375int 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
387WINDOW *bodywin(void)
388{
389 return wbody;
390}
391
392void rmerror(void)
393{
394 rmline(wstat, 0);
395}
396
397void rmstatus(void)
398{
399 rmline(wstat, 1);
400}
401
402void titlemsg(char *msg)
403{
404 mvwaddstr(wtitl, 0, 2, padstr(msg, bw - 3));
405 wrefresh(wtitl);
406}
407
408void bodymsg(char *msg)
409{
410 waddstr(wbody, msg);
411 wrefresh(wbody);
412}
413
414void errormsg(char *msg)
415{
416 beep();
417 mvwaddstr(wstat, 0, 2, padstr(msg, bw - 3));
418 wrefresh(wstat);
419}
420
421void statusmsg(char *msg)
422{
423 mvwaddstr(wstat, 1, 2, padstr(msg, bw - 3));
424 wrefresh(wstat);
425}
426
427bool keypressed(void)
428{
429 ch = wgetch(wbody);
430
431 return ch != ERR;
432}
433
434int 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
445int waitforkey(void)
446{
447 do idle(); while (!keypressed());
448 return getkey();
449}
450
451void DoExit(void) /* terminate program */
452{
453 quit = TRUE;
454}
455
456void 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
555void 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
598static 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
639int 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
809WINDOW *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
823int 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: */