vendor/NCURSES: Remove version tag.
[dragonfly.git] / contrib / ncurses / test / ncurses.c
blob791c3a4157c9eeafec9c2d041a335247e13e1a8f
1 /****************************************************************************
2 * Copyright (c) 1998-2003,2004 Free Software Foundation, Inc. *
3 * *
4 * Permission is hereby granted, free of charge, to any person obtaining a *
5 * copy of this software and associated documentation files (the *
6 * "Software"), to deal in the Software without restriction, including *
7 * without limitation the rights to use, copy, modify, merge, publish, *
8 * distribute, distribute with modifications, sublicense, and/or sell *
9 * copies of the Software, and to permit persons to whom the Software is *
10 * furnished to do so, subject to the following conditions: *
11 * *
12 * The above copyright notice and this permission notice shall be included *
13 * in all copies or substantial portions of the Software. *
14 * *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
22 * *
23 * Except as contained in this notice, the name(s) of the above copyright *
24 * holders shall not be used in advertising or otherwise to promote the *
25 * sale, use or other dealings in this Software without prior written *
26 * authorization. *
27 ****************************************************************************/
28 /****************************************************************************
30 NAME
31 ncurses.c --- ncurses library exerciser
33 SYNOPSIS
34 ncurses
36 DESCRIPTION
37 An interactive test module for the ncurses library.
39 AUTHOR
40 Author: Eric S. Raymond <esr@snark.thyrsus.com> 1993
41 Thomas E. Dickey (beginning revision 1.27 in 1996).
43 $Id: ncurses.c,v 1.202 2004/02/07 20:24:08 tom Exp $
45 ***************************************************************************/
47 #include <test.priv.h>
49 #if HAVE_GETTIMEOFDAY
50 #if HAVE_SYS_TIME_H && HAVE_SYS_TIME_SELECT
51 #include <sys/time.h>
52 #endif
53 #if HAVE_SYS_SELECT_H
54 #include <sys/select.h>
55 #endif
56 #endif
58 #if USE_LIBPANEL
59 #include <panel.h>
60 #endif
62 #if USE_LIBMENU
63 #include <menu.h>
64 #endif
66 #if USE_LIBFORM
67 #include <form.h>
68 #endif
70 #ifdef NCURSES_VERSION
72 #ifdef TRACE
73 static int save_trace = TRACE_ORDINARY | TRACE_CALLS;
74 extern int _nc_tracing;
75 #endif
77 #else
79 #define mmask_t chtype /* not specified in XSI */
81 #ifdef CURSES_ACS_ARRAY
82 #define ACS_S3 (CURSES_ACS_ARRAY['p']) /* scan line 3 */
83 #define ACS_S7 (CURSES_ACS_ARRAY['r']) /* scan line 7 */
84 #define ACS_LEQUAL (CURSES_ACS_ARRAY['y']) /* less/equal */
85 #define ACS_GEQUAL (CURSES_ACS_ARRAY['z']) /* greater/equal */
86 #define ACS_PI (CURSES_ACS_ARRAY['{']) /* Pi */
87 #define ACS_NEQUAL (CURSES_ACS_ARRAY['|']) /* not equal */
88 #define ACS_STERLING (CURSES_ACS_ARRAY['}']) /* UK pound sign */
89 #else
90 #define ACS_S3 (A_ALTCHARSET + 'p') /* scan line 3 */
91 #define ACS_S7 (A_ALTCHARSET + 'r') /* scan line 7 */
92 #define ACS_LEQUAL (A_ALTCHARSET + 'y') /* less/equal */
93 #define ACS_GEQUAL (A_ALTCHARSET + 'z') /* greater/equal */
94 #define ACS_PI (A_ALTCHARSET + '{') /* Pi */
95 #define ACS_NEQUAL (A_ALTCHARSET + '|') /* not equal */
96 #define ACS_STERLING (A_ALTCHARSET + '}') /* UK pound sign */
97 #endif
99 #ifdef CURSES_WACS_ARRAY
100 #define WACS_S3 (&(CURSES_WACS_ARRAY['p'])) /* scan line 3 */
101 #define WACS_S7 (&(CURSES_WACS_ARRAY['r'])) /* scan line 7 */
102 #define WACS_LEQUAL (&(CURSES_WACS_ARRAY['y'])) /* less/equal */
103 #define WACS_GEQUAL (&(CURSES_WACS_ARRAY['z'])) /* greater/equal */
104 #define WACS_PI (&(CURSES_WACS_ARRAY['{'])) /* Pi */
105 #define WACS_NEQUAL (&(CURSES_WACS_ARRAY['|'])) /* not equal */
106 #define WACS_STERLING (&(CURSES_WACS_ARRAY['}'])) /* UK pound sign */
107 #endif
109 #endif
111 #define P(string) printw("%s\n", string)
113 #define BLANK ' ' /* this is the background character */
115 #undef max_colors
116 static int max_colors; /* the actual number of colors we'll use */
118 #undef max_pairs
119 static int max_pairs; /* ...and the number of color pairs */
121 /* The behavior of mvhline, mvvline for negative/zero length is unspecified,
122 * though we can rely on negative x/y values to stop the macro.
124 static void
125 do_h_line(int y, int x, chtype c, int to)
127 if ((to) > (x))
128 mvhline(y, x, c, (to) - (x));
131 static void
132 do_v_line(int y, int x, chtype c, int to)
134 if ((to) > (y))
135 mvvline(y, x, c, (to) - (y));
138 /* Common function to allow ^T to toggle trace-mode in the middle of a test
139 * so that trace-files can be made smaller.
141 static int
142 wGetchar(WINDOW *win)
144 int c;
145 #ifdef TRACE
146 while ((c = wgetch(win)) == CTRL('T')) {
147 if (_nc_tracing) {
148 save_trace = _nc_tracing;
149 _tracef("TOGGLE-TRACING OFF");
150 _nc_tracing = 0;
151 } else {
152 _nc_tracing = save_trace;
154 trace(_nc_tracing);
155 if (_nc_tracing)
156 _tracef("TOGGLE-TRACING ON");
158 #else
159 c = wgetch(win);
160 #endif
161 return c;
163 #define Getchar() wGetchar(stdscr)
165 /* replaces wgetnstr(), since we want to be able to edit values */
166 static void
167 wGetstring(WINDOW *win, char *buffer, int limit)
169 int y0, x0, x, ch;
170 bool done = FALSE;
172 echo();
173 getyx(win, y0, x0);
174 wattrset(win, A_REVERSE);
176 x = strlen(buffer);
177 while (!done) {
178 if (x > (int) strlen(buffer))
179 x = (int) strlen(buffer);
180 wmove(win, y0, x0);
181 wprintw(win, "%-*s", limit, buffer);
182 wmove(win, y0, x0 + x);
183 switch (ch = wGetchar(win)) {
184 case '\n':
185 case KEY_ENTER:
186 done = TRUE;
187 break;
188 case CTRL('U'):
189 *buffer = '\0';
190 break;
191 case '\b':
192 case KEY_BACKSPACE:
193 case KEY_DC:
194 if (x > 0) {
195 int j;
196 for (j = --x; (buffer[j] = buffer[j + 1]) != '\0'; ++j) {
199 } else {
200 beep();
202 break;
203 case KEY_LEFT:
204 if (x > 0) {
205 --x;
206 } else {
207 flash();
209 break;
210 case KEY_RIGHT:
211 ++x;
212 break;
213 default:
214 if (!isprint(ch) || ch >= KEY_MIN) {
215 beep();
216 } else if ((int) strlen(buffer) < limit) {
217 int j;
218 for (j = strlen(buffer) + 1; j > x; --j) {
219 buffer[j] = buffer[j - 1];
221 buffer[x++] = ch;
222 } else {
223 flash();
228 wattroff(win, A_REVERSE);
229 wmove(win, y0, x0);
230 noecho();
233 #if USE_WIDEC_SUPPORT
234 static int
235 wGet_wchar(WINDOW *win, wint_t * result)
237 int c;
238 #ifdef TRACE
239 while ((c = wget_wch(win, result)) == CTRL('T')) {
240 if (_nc_tracing) {
241 save_trace = _nc_tracing;
242 _tracef("TOGGLE-TRACING OFF");
243 _nc_tracing = 0;
244 } else {
245 _nc_tracing = save_trace;
247 trace(_nc_tracing);
248 if (_nc_tracing)
249 _tracef("TOGGLE-TRACING ON");
251 #else
252 c = wget_wch(win, result);
253 #endif
254 return c;
256 #define Get_wchar(result) wGet_wchar(stdscr, result)
258 /* replaces wgetn_wstr(), since we want to be able to edit values */
259 static void
260 wGet_wstring(WINDOW *win, wchar_t * buffer, int limit)
262 int y0, x0, x;
263 wint_t ch;
264 bool done = FALSE;
266 echo();
267 getyx(win, y0, x0);
268 wattrset(win, A_REVERSE);
270 x = wcslen(buffer);
271 while (!done) {
272 if (x > (int) wcslen(buffer))
273 x = (int) wcslen(buffer);
274 wmove(win, y0, x0);
275 waddnwstr(win, buffer, limit);
276 if (x < limit)
277 wprintw(win, "%*s", limit - x, " ");
278 wmove(win, y0, x0 + x);
279 switch (wGet_wchar(win, &ch)) {
280 case KEY_CODE_YES:
281 switch (ch) {
282 case KEY_ENTER:
283 ch = '\n';
284 break;
285 case KEY_BACKSPACE:
286 case KEY_DC:
287 ch = '\b';
288 break;
289 case KEY_LEFT:
290 case KEY_RIGHT:
291 break;
292 default:
293 ch = (wint_t) - 1;
294 break;
296 case OK:
297 break;
298 default:
299 ch = (wint_t) - 1;
300 break;
303 switch (ch) {
304 case '\n':
305 done = TRUE;
306 break;
307 case CTRL('U'):
308 *buffer = '\0';
309 break;
310 case '\b':
311 if (x > 0) {
312 int j;
313 for (j = --x; (buffer[j] = buffer[j + 1]) != '\0'; ++j) {
316 } else {
317 beep();
319 break;
320 case KEY_LEFT:
321 if (x > 0) {
322 --x;
323 } else {
324 flash();
326 break;
327 case KEY_RIGHT:
328 ++x;
329 break;
330 default:
331 if (!isprint(ch) || ch >= KEY_MIN) {
332 beep();
333 } else if ((int) wcslen(buffer) < limit) {
334 int j;
335 for (j = wcslen(buffer) + 1; j > x; --j) {
336 buffer[j] = buffer[j - 1];
338 buffer[x++] = ch;
339 } else {
340 flash();
345 wattroff(win, A_REVERSE);
346 wmove(win, y0, x0);
347 noecho();
350 #endif
352 static void
353 Pause(void)
355 move(LINES - 1, 0);
356 addstr("Press any key to continue... ");
357 (void) Getchar();
360 static void
361 Cannot(const char *what)
363 printw("\nThis %s terminal %s\n\n", getenv("TERM"), what);
364 Pause();
367 static void
368 ShellOut(bool message)
370 if (message)
371 addstr("Shelling out...");
372 def_prog_mode();
373 endwin();
374 system("sh");
375 if (message)
376 addstr("returned from shellout.\n");
377 refresh();
380 #ifdef NCURSES_MOUSE_VERSION
381 static const char *
382 mouse_decode(MEVENT const *ep)
384 static char buf[80];
386 (void) sprintf(buf, "id %2d at (%2d, %2d, %2d) state %4lx = {",
387 ep->id, ep->x, ep->y, ep->z, ep->bstate);
389 #define SHOW(m, s) if ((ep->bstate & m)==m) {strcat(buf,s); strcat(buf, ", ");}
390 SHOW(BUTTON1_RELEASED, "release-1");
391 SHOW(BUTTON1_PRESSED, "press-1");
392 SHOW(BUTTON1_CLICKED, "click-1");
393 SHOW(BUTTON1_DOUBLE_CLICKED, "doubleclick-1");
394 SHOW(BUTTON1_TRIPLE_CLICKED, "tripleclick-1");
395 SHOW(BUTTON1_RESERVED_EVENT, "reserved-1");
396 SHOW(BUTTON2_RELEASED, "release-2");
397 SHOW(BUTTON2_PRESSED, "press-2");
398 SHOW(BUTTON2_CLICKED, "click-2");
399 SHOW(BUTTON2_DOUBLE_CLICKED, "doubleclick-2");
400 SHOW(BUTTON2_TRIPLE_CLICKED, "tripleclick-2");
401 SHOW(BUTTON2_RESERVED_EVENT, "reserved-2");
402 SHOW(BUTTON3_RELEASED, "release-3");
403 SHOW(BUTTON3_PRESSED, "press-3");
404 SHOW(BUTTON3_CLICKED, "click-3");
405 SHOW(BUTTON3_DOUBLE_CLICKED, "doubleclick-3");
406 SHOW(BUTTON3_TRIPLE_CLICKED, "tripleclick-3");
407 SHOW(BUTTON3_RESERVED_EVENT, "reserved-3");
408 SHOW(BUTTON4_RELEASED, "release-4");
409 SHOW(BUTTON4_PRESSED, "press-4");
410 SHOW(BUTTON4_CLICKED, "click-4");
411 SHOW(BUTTON4_DOUBLE_CLICKED, "doubleclick-4");
412 SHOW(BUTTON4_TRIPLE_CLICKED, "tripleclick-4");
413 SHOW(BUTTON4_RESERVED_EVENT, "reserved-4");
414 SHOW(BUTTON_CTRL, "ctrl");
415 SHOW(BUTTON_SHIFT, "shift");
416 SHOW(BUTTON_ALT, "alt");
417 SHOW(ALL_MOUSE_EVENTS, "all-events");
418 SHOW(REPORT_MOUSE_POSITION, "position");
419 #undef SHOW
421 if (buf[strlen(buf) - 1] == ' ')
422 buf[strlen(buf) - 2] = '\0';
423 (void) strcat(buf, "}");
424 return (buf);
426 #endif /* NCURSES_MOUSE_VERSION */
428 /****************************************************************************
430 * Character input test
432 ****************************************************************************/
434 static void
435 setup_getch(WINDOW *win, bool flags[])
437 keypad(win, flags['k']); /* should be redundant, but for testing */
438 meta(win, flags['m']); /* force this to a known state */
439 if (flags['e'])
440 echo();
441 else
442 noecho();
445 static void
446 wgetch_help(WINDOW *win, bool flags[])
448 static const char *help[] =
450 "e -- toggle echo mode"
451 ,"g -- triggers a getstr test"
452 ,"k -- toggle keypad/literal mode"
453 ,"m -- toggle meta (7-bit/8-bit) mode"
454 ,"q -- quit (x also exits)"
455 ,"s -- shell out\n"
456 ,"w -- create a new window"
457 #ifdef SIGTSTP
458 ,"z -- suspend this process"
459 #endif
461 int y, x;
462 unsigned chk = ((SIZEOF(help) + 1) / 2);
463 unsigned n;
465 getyx(win, y, x);
466 move(0, 0);
467 printw("Type any key to see its %s value. Also:\n",
468 flags['k'] ? "keypad" : "literal");
469 for (n = 0; n < SIZEOF(help); ++n) {
470 int row = 1 + (n % chk);
471 int col = (n >= chk) ? COLS / 2 : 0;
472 int flg = ((strstr(help[n], "toggle") != 0)
473 && (flags[UChar(*help[n])] != FALSE));
474 if (flg)
475 standout();
476 mvprintw(row, col, "%s", help[n]);
477 if (col == 0)
478 clrtoeol();
479 if (flg)
480 standend();
482 wrefresh(stdscr);
483 wmove(win, y, x);
486 static void
487 wgetch_wrap(WINDOW *win, int first_y)
489 int last_y = getmaxy(win) - 1;
490 int y = getcury(win) + 1;
492 if (y >= last_y)
493 y = first_y;
494 wmove(win, y, 0);
495 wclrtoeol(win);
498 #if defined(NCURSES_VERSION) && defined(KEY_RESIZE) && HAVE_WRESIZE
499 typedef struct {
500 WINDOW *text;
501 WINDOW *frame;
502 } WINSTACK;
504 static WINSTACK *winstack = 0;
505 static unsigned len_winstack = 0;
507 static void
508 remember_boxes(unsigned level, WINDOW *txt_win, WINDOW *box_win)
510 unsigned need = (level + 1) * 2;
512 if (winstack == 0) {
513 len_winstack = 20;
514 winstack = (WINSTACK *) malloc(len_winstack * sizeof(WINSTACK));
515 } else if (need >= len_winstack) {
516 len_winstack = need;
517 winstack = (WINSTACK *) realloc(winstack, len_winstack * sizeof(WINSTACK));
519 winstack[level].text = txt_win;
520 winstack[level].frame = box_win;
524 * For wgetch_test(), we create pairs of windows - one for a box, one for text.
525 * Resize both and paint the box in the parent.
527 static void
528 resize_boxes(int level, WINDOW *win)
530 unsigned n;
531 int base = 5;
532 int high = LINES - base;
533 int wide = COLS;
535 touchwin(stdscr);
536 wnoutrefresh(stdscr);
538 /* FIXME: this chunk should be done in resizeterm() */
539 slk_touch();
540 slk_clear();
541 slk_noutrefresh();
543 for (n = 0; (int) n < level; ++n) {
544 wresize(winstack[n].frame, high, wide);
545 wresize(winstack[n].text, high - 2, wide - 2);
546 high -= 2;
547 wide -= 2;
548 werase(winstack[n].text);
549 box(winstack[n].frame, 0, 0);
550 wnoutrefresh(winstack[n].frame);
551 wprintw(winstack[n].text,
552 "size %dx%d\n",
553 getmaxy(winstack[n].text),
554 getmaxx(winstack[n].text));
555 wnoutrefresh(winstack[n].text);
556 if (winstack[n].text == win)
557 break;
559 doupdate();
561 #else
562 #define remember_boxes(level,text,frame) /* nothing */
563 #endif
565 static void
566 wgetch_test(int level, WINDOW *win, int delay)
568 char buf[BUFSIZ];
569 int first_y, first_x;
570 int c;
571 int incount = 0;
572 bool flags[256];
573 bool blocking = (delay < 0);
574 int y, x;
576 memset(flags, FALSE, sizeof(flags));
577 flags[UChar('k')] = (win == stdscr);
579 setup_getch(win, flags);
580 wtimeout(win, delay);
581 getyx(win, first_y, first_x);
583 wgetch_help(win, flags);
584 wsetscrreg(win, first_y, getmaxy(win) - 1);
585 scrollok(win, TRUE);
587 for (;;) {
588 while ((c = wGetchar(win)) == ERR) {
589 incount++;
590 if (blocking) {
591 (void) wprintw(win, "%05d: input error", incount);
592 break;
593 } else {
594 (void) wprintw(win, "%05d: input timed out", incount);
596 wgetch_wrap(win, first_y);
598 if (c == ERR && blocking) {
599 wprintw(win, "ERR");
600 wgetch_wrap(win, first_y);
601 } else if (c == 'x' || c == 'q') {
602 break;
603 } else if (c == 'e') {
604 flags[UChar('e')] = !flags[UChar('e')];
605 setup_getch(win, flags);
606 wgetch_help(win, flags);
607 } else if (c == 'g') {
608 waddstr(win, "getstr test: ");
609 echo();
610 wgetnstr(win, buf, sizeof(buf) - 1);
611 noecho();
612 wprintw(win, "I saw %d characters:\n\t`%s'.", (int) strlen(buf), buf);
613 wclrtoeol(win);
614 wgetch_wrap(win, first_y);
615 } else if (c == 'k') {
616 flags[UChar('k')] = !flags[UChar('k')];
617 setup_getch(win, flags);
618 wgetch_help(win, flags);
619 } else if (c == 'm') {
620 flags[UChar('m')] = !flags[UChar('m')];
621 setup_getch(win, flags);
622 wgetch_help(win, flags);
623 } else if (c == 's') {
624 ShellOut(TRUE);
625 } else if (c == 'w') {
626 int high = getmaxy(win) - 1 - first_y + 1;
627 int wide = getmaxx(win) - first_x;
628 int old_y, old_x;
629 int new_y = first_y + getbegy(win);
630 int new_x = first_x + getbegx(win);
632 getyx(win, old_y, old_x);
633 if (high > 2 && wide > 2) {
634 WINDOW *wb = newwin(high, wide, new_y, new_x);
635 WINDOW *wi = newwin(high - 2, wide - 2, new_y + 1, new_x + 1);
637 box(wb, 0, 0);
638 wrefresh(wb);
639 wmove(wi, 0, 0);
640 remember_boxes(level, wi, wb);
641 wgetch_test(level + 1, wi, delay);
642 delwin(wi);
643 delwin(wb);
645 wgetch_help(win, flags);
646 wmove(win, old_y, old_x);
647 touchwin(win);
648 wrefresh(win);
649 doupdate();
651 #ifdef SIGTSTP
652 } else if (c == 'z') {
653 kill(getpid(), SIGTSTP);
654 #endif
655 } else {
656 wprintw(win, "Key pressed: %04o ", c);
657 #ifdef NCURSES_MOUSE_VERSION
658 if (c == KEY_MOUSE) {
659 MEVENT event;
661 getmouse(&event);
662 wprintw(win, "KEY_MOUSE, %s", mouse_decode(&event));
663 getyx(win, y, x);
664 move(event.y, event.x);
665 addch('*');
666 wmove(win, y, x);
667 } else
668 #endif /* NCURSES_MOUSE_VERSION */
669 if (c >= KEY_MIN) {
670 #if defined(NCURSES_VERSION) && defined(KEY_RESIZE) && HAVE_WRESIZE
671 if (c == KEY_RESIZE) {
672 resize_boxes(level, win);
674 #endif
675 (void) waddstr(win, keyname(c));
676 } else if (c > 0x80) {
677 int c2 = (c & 0x7f);
678 if (isprint(c2))
679 (void) wprintw(win, "M-%c", c2);
680 else
681 (void) wprintw(win, "M-%s", unctrl(c2));
682 waddstr(win, " (high-half character)");
683 } else {
684 if (isprint(c))
685 (void) wprintw(win, "%c (ASCII printable character)", c);
686 else
687 (void) wprintw(win, "%s (ASCII control character)",
688 unctrl(c));
690 wgetch_wrap(win, first_y);
694 wtimeout(win, -1);
697 static int
698 begin_getch_test(void)
700 char buf[BUFSIZ];
701 int delay;
703 refresh();
705 #ifdef NCURSES_MOUSE_VERSION
706 mousemask(ALL_MOUSE_EVENTS, (mmask_t *) 0);
707 #endif
709 (void) printw("Delay in 10ths of a second (<CR> for blocking input)? ");
710 echo();
711 getnstr(buf, sizeof(buf) - 1);
712 noecho();
713 nonl();
715 if (isdigit(UChar(buf[0]))) {
716 delay = atoi(buf) * 100;
717 } else {
718 delay = -1;
720 raw();
721 move(5, 0);
722 return delay;
725 static void
726 finish_getch_test(void)
728 #ifdef NCURSES_MOUSE_VERSION
729 mousemask(0, (mmask_t *) 0);
730 #endif
731 erase();
732 noraw();
733 nl();
734 endwin();
737 static void
738 getch_test(void)
740 int delay = begin_getch_test();
741 wgetch_test(0, stdscr, delay);
742 finish_getch_test();
745 #if USE_WIDEC_SUPPORT
747 * For wgetch_test(), we create pairs of windows - one for a box, one for text.
748 * Resize both and paint the box in the parent.
750 #ifdef KEY_RESIZE
751 static void
752 resize_wide_boxes(int level, WINDOW *win)
754 unsigned n;
755 int base = 5;
756 int high = LINES - base;
757 int wide = COLS;
759 touchwin(stdscr);
760 wnoutrefresh(stdscr);
762 /* FIXME: this chunk should be done in resizeterm() */
763 slk_touch();
764 slk_clear();
765 slk_noutrefresh();
767 for (n = 0; (int) n < level; ++n) {
768 wresize(winstack[n].frame, high, wide);
769 wresize(winstack[n].text, high - 2, wide - 2);
770 high -= 2;
771 wide -= 2;
772 werase(winstack[n].text);
773 box_set(winstack[n].frame, 0, 0);
774 wnoutrefresh(winstack[n].frame);
775 wprintw(winstack[n].text,
776 "size %dx%d\n",
777 getmaxy(winstack[n].text),
778 getmaxx(winstack[n].text));
779 wnoutrefresh(winstack[n].text);
780 if (winstack[n].text == win)
781 break;
783 doupdate();
785 #endif /* KEY_RESIZE */
787 static char *
788 wcstos(const wchar_t * src)
790 int need;
791 mbstate_t state;
792 char *result = 0;
793 const wchar_t *tmp = src;
795 memset(&state, 0, sizeof(state));
796 if ((need = wcsrtombs(0, &tmp, 0, &state)) > 0) {
797 result = (char *) calloc(need + 1, 1);
798 tmp = src;
799 if (wcsrtombs(result, &tmp, need, &state) != (size_t) need) {
800 free(result);
801 result = 0;
804 return result;
807 static void
808 wget_wch_test(int level, WINDOW *win, int delay)
810 wchar_t buf[BUFSIZ];
811 int first_y, first_x;
812 wint_t c;
813 int incount = 0;
814 bool flags[256];
815 bool blocking = (delay < 0);
816 int y, x, code;
817 char *temp;
819 memset(flags, FALSE, sizeof(flags));
820 flags[UChar('k')] = (win == stdscr);
822 setup_getch(win, flags);
823 wtimeout(win, delay);
824 getyx(win, first_y, first_x);
826 wgetch_help(win, flags);
827 wsetscrreg(win, first_y, getmaxy(win) - 1);
828 scrollok(win, TRUE);
830 for (;;) {
831 while ((code = wGet_wchar(win, &c)) == ERR) {
832 incount++;
833 if (blocking) {
834 (void) wprintw(win, "%05d: input error", incount);
835 break;
836 } else {
837 (void) wprintw(win, "%05d: input timed out", incount);
839 wgetch_wrap(win, first_y);
841 if (code == ERR && blocking) {
842 wprintw(win, "ERR");
843 wgetch_wrap(win, first_y);
844 } else if (c == 'x' || c == 'q') {
845 break;
846 } else if (c == 'e') {
847 flags[UChar('e')] = !flags[UChar('e')];
848 setup_getch(win, flags);
849 wgetch_help(win, flags);
850 } else if (c == 'g') {
851 waddstr(win, "getstr test: ");
852 echo();
853 wgetn_wstr(win, (wint_t *) buf, sizeof(buf) - 1);
854 noecho();
855 if ((temp = wcstos(buf)) != 0) {
856 wprintw(win, "I saw %d characters:\n\t`%s'.", wcslen(buf), temp);
857 free(temp);
858 } else {
859 wprintw(win, "I saw %d characters (cannot convert).", wcslen(buf));
861 wclrtoeol(win);
862 wgetch_wrap(win, first_y);
863 } else if (c == 'k') {
864 flags[UChar('k')] = !flags[UChar('k')];
865 setup_getch(win, flags);
866 wgetch_help(win, flags);
867 } else if (c == 'm') {
868 flags[UChar('m')] = !flags[UChar('m')];
869 setup_getch(win, flags);
870 wgetch_help(win, flags);
871 } else if (c == 's') {
872 ShellOut(TRUE);
873 } else if (c == 'w') {
874 int high = getmaxy(win) - 1 - first_y + 1;
875 int wide = getmaxx(win) - first_x;
876 int old_y, old_x;
877 int new_y = first_y + getbegy(win);
878 int new_x = first_x + getbegx(win);
880 getyx(win, old_y, old_x);
881 if (high > 2 && wide > 2) {
882 WINDOW *wb = newwin(high, wide, new_y, new_x);
883 WINDOW *wi = newwin(high - 2, wide - 2, new_y + 1, new_x + 1);
885 box_set(wb, 0, 0);
886 wrefresh(wb);
887 wmove(wi, 0, 0);
888 remember_boxes(level, wi, wb);
889 wget_wch_test(level + 1, wi, delay);
890 delwin(wi);
891 delwin(wb);
893 wgetch_help(win, flags);
894 wmove(win, old_y, old_x);
895 touchwin(win);
896 wrefresh(win);
898 #ifdef SIGTSTP
899 } else if (c == 'z') {
900 kill(getpid(), SIGTSTP);
901 #endif
902 } else {
903 wprintw(win, "Key pressed: %04o ", c);
904 #ifdef NCURSES_MOUSE_VERSION
905 if (c == KEY_MOUSE) {
906 MEVENT event;
908 getmouse(&event);
909 wprintw(win, "KEY_MOUSE, %s", mouse_decode(&event));
910 getyx(win, y, x);
911 move(event.y, event.x);
912 addch('*');
913 wmove(win, y, x);
914 } else
915 #endif /* NCURSES_MOUSE_VERSION */
916 if (code == KEY_CODE_YES) {
917 #ifdef KEY_RESIZE
918 if (c == KEY_RESIZE) {
919 resize_wide_boxes(level, win);
921 #endif
922 (void) waddstr(win, key_name(c));
923 } else {
924 if (c < 256 && iscntrl(c)) {
925 (void) wprintw(win, "%s (control character)", unctrl(c));
926 } else {
927 wchar_t c2 = c;
928 waddnwstr(win, &c2, 1);
929 (void) wprintw(win, " = %#x (printable character)", c);
932 wgetch_wrap(win, first_y);
936 wtimeout(win, -1);
939 static void
940 get_wch_test(void)
942 int delay = begin_getch_test();
943 wget_wch_test(0, stdscr, delay);
944 finish_getch_test();
946 #endif
948 /****************************************************************************
950 * Character attributes test
952 ****************************************************************************/
954 #define MAX_ATTRSTRING 31
955 #define LEN_ATTRSTRING 26
957 static char attr_test_string[] = "abcde fghij klmno pqrst uvwxy z";
959 static void
960 adjust_attr_string(int adjust)
962 int first = ((int) UChar(attr_test_string[0])) + adjust;
963 int last = first + LEN_ATTRSTRING;
965 if (first >= ' ' && last <= '~') { /* 32..126 */
966 int j, k;
967 for (j = 0, k = first; k <= last; ++j, ++k) {
968 attr_test_string[j] = k;
969 if (((k + 1 - first) % 5) == 0) {
970 ++j;
971 if (j < MAX_ATTRSTRING)
972 attr_test_string[j] = ' ';
975 while (j < MAX_ATTRSTRING)
976 attr_test_string[j++] = ' ';
977 attr_test_string[j] = '\0';
978 } else {
979 beep();
983 static int
984 show_attr(int row, int skip, chtype attr, const char *name)
986 int ncv = tigetnum("ncv");
987 chtype test = attr & ~A_ALTCHARSET;
989 mvprintw(row, 8, "%s mode:", name);
990 mvprintw(row, 24, "|");
991 if (skip)
992 printw("%*s", skip, " ");
993 attrset(attr);
995 * If we're to write a string in the alternate character set, it is not
996 * sufficient to just set A_ALTCHARSET. We have to perform the mapping
997 * that corresponds. This is not needed for vt100-compatible devices
998 * because the acs_map[] is 1:1, but for PC-style devices such as Linux
999 * console, the acs_map[] is scattered about the range.
1001 * The addch/addstr functions do not themselves do this mapping, since it
1002 * is possible to turn off the A_ALTCHARSET flag for the characters which
1003 * are added, and it would be an unexpected result to have the mapped
1004 * characters visible on the screen.
1006 if (attr & A_ALTCHARSET) {
1007 const char *s;
1008 int ch;
1010 for (s = attr_test_string; *s != '\0'; ++s) {
1011 ch = UChar(*s);
1012 addch(ch);
1014 } else {
1015 addstr(attr_test_string);
1017 attroff(attr);
1018 if (skip)
1019 printw("%*s", skip, " ");
1020 printw("|");
1021 if (test != A_NORMAL) {
1022 if (!(termattrs() & test)) {
1023 printw(" (N/A)");
1024 } else if (ncv > 0 && (getbkgd(stdscr) & A_COLOR)) {
1025 static const chtype table[] =
1027 A_STANDOUT,
1028 A_UNDERLINE,
1029 A_REVERSE,
1030 A_BLINK,
1031 A_DIM,
1032 A_BOLD,
1033 A_INVIS,
1034 A_PROTECT,
1035 A_ALTCHARSET
1037 unsigned n;
1038 bool found = FALSE;
1039 for (n = 0; n < SIZEOF(table); n++) {
1040 if ((table[n] & attr) != 0
1041 && ((1 << n) & ncv) != 0) {
1042 found = TRUE;
1043 break;
1046 if (found)
1047 printw(" (NCV)");
1050 return row + 2;
1053 static bool
1054 attr_getc(int *skip, int *fg, int *bg, int *ac)
1056 int ch = Getchar();
1058 if (isdigit(ch)) {
1059 *skip = (ch - '0');
1060 } else if (ch == CTRL('L')) {
1061 touchwin(stdscr);
1062 touchwin(curscr);
1063 wrefresh(curscr);
1064 } else {
1065 switch (ch) {
1066 case 'a':
1067 *ac = 0;
1068 break;
1069 case 'A':
1070 *ac = A_ALTCHARSET;
1071 break;
1072 case '<':
1073 adjust_attr_string(-1);
1074 break;
1075 case '>':
1076 adjust_attr_string(1);
1077 break;
1078 default:
1079 if (has_colors()) {
1080 switch (ch) {
1081 case 'f':
1082 *fg = (*fg + 1);
1083 break;
1084 case 'F':
1085 *fg = (*fg - 1);
1086 break;
1087 case 'b':
1088 *bg = (*bg + 1);
1089 break;
1090 case 'B':
1091 *bg = (*bg - 1);
1092 break;
1093 default:
1094 return FALSE;
1096 if (*fg >= max_colors)
1097 *fg = 0;
1098 if (*fg < 0)
1099 *fg = max_colors - 1;
1100 if (*bg >= max_colors)
1101 *bg = 0;
1102 if (*bg < 0)
1103 *bg = max_colors - 1;
1105 break;
1108 return TRUE;
1111 static void
1112 attr_test(void)
1113 /* test text attributes */
1115 int n;
1116 int skip = tigetnum("xmc");
1117 int fg = COLOR_BLACK; /* color pair 0 is special */
1118 int bg = COLOR_BLACK;
1119 int ac = 0;
1120 bool *pairs = (bool *) calloc(max_pairs, sizeof(bool));
1121 pairs[0] = TRUE;
1123 if (skip < 0)
1124 skip = 0;
1126 n = skip; /* make it easy */
1128 do {
1129 int row = 2;
1130 int normal = A_NORMAL | BLANK;
1132 if (has_colors()) {
1133 int pair = (fg * max_colors) + bg;
1134 if (!pairs[pair]) {
1135 init_pair(pair, fg, bg);
1136 pairs[pair] = TRUE;
1138 normal |= COLOR_PAIR(pair);
1140 bkgd(normal);
1141 bkgdset(normal);
1142 erase();
1144 box(stdscr, 0, 0);
1145 mvaddstr(0, 20, "Character attribute test display");
1147 row = show_attr(row, n, ac | A_STANDOUT, "STANDOUT");
1148 row = show_attr(row, n, ac | A_REVERSE, "REVERSE");
1149 row = show_attr(row, n, ac | A_BOLD, "BOLD");
1150 row = show_attr(row, n, ac | A_UNDERLINE, "UNDERLINE");
1151 row = show_attr(row, n, ac | A_DIM, "DIM");
1152 row = show_attr(row, n, ac | A_BLINK, "BLINK");
1153 row = show_attr(row, n, ac | A_PROTECT, "PROTECT");
1154 row = show_attr(row, n, ac | A_INVIS, "INVISIBLE");
1155 row = show_attr(row, n, ac | A_NORMAL, "NORMAL");
1157 mvprintw(row, 8,
1158 "This terminal does %shave the magic-cookie glitch",
1159 tigetnum("xmc") > -1 ? "" : "not ");
1160 mvprintw(row + 1, 8,
1161 "Enter a digit to set gaps on each side of displayed attributes");
1162 mvprintw(row + 2, 8,
1163 "^L repaints, </> shifts, ");
1164 if (has_colors())
1165 printw("f/F/b/F toggle color (now %d/%d), a/A ACS (%d)",
1166 fg, bg, ac != 0);
1167 else
1168 printw("a/A ACS (%d)", ac != 0);
1170 refresh();
1171 } while (attr_getc(&n, &fg, &bg, &ac));
1173 free((char *) pairs);
1174 bkgdset(A_NORMAL | BLANK);
1175 erase();
1176 endwin();
1179 /****************************************************************************
1181 * Color support tests
1183 ****************************************************************************/
1185 static NCURSES_CONST char *the_color_names[] =
1187 "black",
1188 "red",
1189 "green",
1190 "yellow",
1191 "blue",
1192 "magenta",
1193 "cyan",
1194 "white",
1195 "BLACK",
1196 "RED",
1197 "GREEN",
1198 "YELLOW",
1199 "BLUE",
1200 "MAGENTA",
1201 "CYAN",
1202 "WHITE"
1205 static void
1206 show_color_name(int y, int x, int color)
1208 if (max_colors > 8)
1209 mvprintw(y, x, "%02d ", color);
1210 else
1211 mvaddstr(y, x, the_color_names[color]);
1214 static void
1215 color_test(void)
1216 /* generate a color test pattern */
1218 int i;
1219 int base, top, width;
1220 const char *hello;
1222 refresh();
1223 (void) printw("There are %d color pairs\n", COLOR_PAIRS);
1225 width = (max_colors > 8) ? 4 : 8;
1226 hello = (max_colors > 8) ? "Test" : "Hello";
1228 for (base = 0; base < 2; base++) {
1229 top = (max_colors > 8) ? 0 : base * (max_colors + 3);
1230 clrtobot();
1231 (void) mvprintw(top + 1, 0,
1232 "%dx%d matrix of foreground/background colors, bright *%s*\n",
1233 max_colors, max_colors,
1234 base ? "on" : "off");
1235 for (i = 0; i < max_colors; i++)
1236 show_color_name(top + 2, (i + 1) * width, i);
1237 for (i = 0; i < max_colors; i++)
1238 show_color_name(top + 3 + i, 0, i);
1239 for (i = 1; i < max_pairs; i++) {
1240 init_pair(i, i % max_colors, i / max_colors);
1241 attron((attr_t) COLOR_PAIR(i));
1242 if (base)
1243 attron((attr_t) A_BOLD);
1244 mvaddstr(top + 3 + (i / max_colors), (i % max_colors + 1) *
1245 width, hello);
1246 attrset(A_NORMAL);
1248 if ((max_colors > 8) || base)
1249 Pause();
1252 erase();
1253 endwin();
1256 static void
1257 change_color(int current, int field, int value, int usebase)
1259 short red, green, blue;
1261 if (usebase)
1262 color_content(current, &red, &green, &blue);
1263 else
1264 red = green = blue = 0;
1266 switch (field) {
1267 case 0:
1268 red += value;
1269 break;
1270 case 1:
1271 green += value;
1272 break;
1273 case 2:
1274 blue += value;
1275 break;
1278 if (init_color(current, red, green, blue) == ERR)
1279 beep();
1282 static void
1283 color_edit(void)
1284 /* display the color test pattern, without trying to edit colors */
1286 int i, this_c = 0, value = 0, current = 0, field = 0;
1287 int last_c;
1289 refresh();
1291 for (i = 0; i < max_colors; i++)
1292 init_pair(i, COLOR_WHITE, i);
1294 mvprintw(LINES - 2, 0, "Number: %d", value);
1296 do {
1297 short red, green, blue;
1299 attron(A_BOLD);
1300 mvaddstr(0, 20, "Color RGB Value Editing");
1301 attroff(A_BOLD);
1303 for (i = 0; i < max_colors; i++) {
1304 mvprintw(2 + i, 0, "%c %-8s:",
1305 (i == current ? '>' : ' '),
1306 (i < (int) SIZEOF(the_color_names)
1307 ? the_color_names[i] : ""));
1308 attrset(COLOR_PAIR(i));
1309 addstr(" ");
1310 attrset(A_NORMAL);
1313 * Note: this refresh should *not* be necessary! It works around
1314 * a bug in attribute handling that apparently causes the A_NORMAL
1315 * attribute sets to interfere with the actual emission of the
1316 * color setting somehow. This needs to be fixed.
1318 refresh();
1320 color_content(i, &red, &green, &blue);
1321 addstr(" R = ");
1322 if (current == i && field == 0)
1323 attron(A_STANDOUT);
1324 printw("%04d", red);
1325 if (current == i && field == 0)
1326 attrset(A_NORMAL);
1327 addstr(", G = ");
1328 if (current == i && field == 1)
1329 attron(A_STANDOUT);
1330 printw("%04d", green);
1331 if (current == i && field == 1)
1332 attrset(A_NORMAL);
1333 addstr(", B = ");
1334 if (current == i && field == 2)
1335 attron(A_STANDOUT);
1336 printw("%04d", blue);
1337 if (current == i && field == 2)
1338 attrset(A_NORMAL);
1339 attrset(A_NORMAL);
1340 addstr(")");
1343 mvaddstr(max_colors + 3, 0,
1344 "Use up/down to select a color, left/right to change fields.");
1345 mvaddstr(max_colors + 4, 0,
1346 "Modify field by typing nnn=, nnn-, or nnn+. ? for help.");
1348 move(2 + current, 0);
1350 last_c = this_c;
1351 this_c = Getchar();
1352 if (isdigit(this_c) && !isdigit(last_c))
1353 value = 0;
1355 switch (this_c) {
1356 case KEY_UP:
1357 current = (current == 0 ? (max_colors - 1) : current - 1);
1358 break;
1360 case KEY_DOWN:
1361 current = (current == (max_colors - 1) ? 0 : current + 1);
1362 break;
1364 case KEY_RIGHT:
1365 field = (field == 2 ? 0 : field + 1);
1366 break;
1368 case KEY_LEFT:
1369 field = (field == 0 ? 2 : field - 1);
1370 break;
1372 case '0':
1373 case '1':
1374 case '2':
1375 case '3':
1376 case '4':
1377 case '5':
1378 case '6':
1379 case '7':
1380 case '8':
1381 case '9':
1382 value = value * 10 + (this_c - '0');
1383 break;
1385 case '+':
1386 change_color(current, field, value, 1);
1387 break;
1389 case '-':
1390 change_color(current, field, -value, 1);
1391 break;
1393 case '=':
1394 change_color(current, field, value, 0);
1395 break;
1397 case '?':
1398 erase();
1399 P(" RGB Value Editing Help");
1400 P("");
1401 P("You are in the RGB value editor. Use the arrow keys to select one of");
1402 P("the fields in one of the RGB triples of the current colors; the one");
1403 P("currently selected will be reverse-video highlighted.");
1404 P("");
1405 P("To change a field, enter the digits of the new value; they are echoed");
1406 P("as entered. Finish by typing `='. The change will take effect instantly.");
1407 P("To increment or decrement a value, use the same procedure, but finish");
1408 P("with a `+' or `-'.");
1409 P("");
1410 P("To quit, do `x' or 'q'");
1412 Pause();
1413 erase();
1414 break;
1416 case 'x':
1417 case 'q':
1418 break;
1420 default:
1421 beep();
1422 break;
1424 mvprintw(LINES - 2, 0, "Number: %d", value);
1425 clrtoeol();
1426 } while
1427 (this_c != 'x' && this_c != 'q');
1429 erase();
1430 endwin();
1433 /****************************************************************************
1435 * Soft-key label test
1437 ****************************************************************************/
1439 #define SLK_HELP 17
1440 #define SLK_WORK (SLK_HELP + 3)
1442 static void
1443 slk_help(void)
1445 static const char *table[] =
1447 "Available commands are:"
1449 ,"^L -- repaint this message and activate soft keys"
1450 ,"a/d -- activate/disable soft keys"
1451 ,"c -- set centered format for labels"
1452 ,"l -- set left-justified format for labels"
1453 ,"r -- set right-justified format for labels"
1454 ,"[12345678] -- set label; labels are numbered 1 through 8"
1455 ,"e -- erase stdscr (should not erase labels)"
1456 ,"s -- test scrolling of shortened screen"
1457 #if HAVE_SLK_COLOR
1458 ,"F/B -- cycle through foreground/background colors"
1459 #endif
1460 ,"x, q -- return to main menu"
1462 ,"Note: if activating the soft keys causes your terminal to scroll up"
1463 ,"one line, your terminal auto-scrolls when anything is written to the"
1464 ,"last screen position. The ncurses code does not yet handle this"
1465 ,"gracefully."
1467 unsigned j;
1469 move(2, 0);
1470 for (j = 0; j < SIZEOF(table); ++j) {
1471 P(table[j]);
1473 refresh();
1476 static void
1477 slk_test(void)
1478 /* exercise the soft keys */
1480 int c, fmt = 1;
1481 char buf[9];
1482 char *s;
1483 #if HAVE_SLK_COLOR
1484 short fg = COLOR_BLACK;
1485 short bg = COLOR_WHITE;
1486 bool new_color = FALSE;
1487 #endif
1489 c = CTRL('l');
1490 #if HAVE_SLK_COLOR
1491 if (has_colors()) {
1492 new_color = TRUE;
1494 #endif
1496 do {
1497 #if HAVE_SLK_COLOR
1498 if (new_color) {
1499 init_pair(1, bg, fg);
1500 slk_color(1);
1501 new_color = FALSE;
1502 mvprintw(SLK_WORK, 0, "Colors %d/%d\n", fg, bg);
1503 refresh();
1505 #endif
1506 move(0, 0);
1507 switch (c) {
1508 case CTRL('l'):
1509 erase();
1510 attron(A_BOLD);
1511 mvaddstr(0, 20, "Soft Key Exerciser");
1512 attroff(A_BOLD);
1514 slk_help();
1515 /* fall through */
1517 case 'a':
1518 slk_restore();
1519 break;
1521 case 'e':
1522 wclear(stdscr);
1523 break;
1525 case 's':
1526 mvprintw(SLK_WORK, 0, "Press Q to stop the scrolling-test: ");
1527 while ((c = Getchar()) != 'Q' && (c != ERR))
1528 addch((chtype) c);
1529 break;
1531 case 'd':
1532 slk_clear();
1533 break;
1535 case 'l':
1536 fmt = 0;
1537 break;
1539 case 'c':
1540 fmt = 1;
1541 break;
1543 case 'r':
1544 fmt = 2;
1545 break;
1547 case '1':
1548 case '2':
1549 case '3':
1550 case '4':
1551 case '5':
1552 case '6':
1553 case '7':
1554 case '8':
1555 (void) mvaddstr(SLK_WORK, 0, "Please enter the label value: ");
1556 strcpy(buf, "");
1557 if ((s = slk_label(c - '0')) != 0) {
1558 strncpy(buf, s, 8);
1560 wGetstring(stdscr, buf, 8);
1561 slk_set((c - '0'), buf, fmt);
1562 slk_refresh();
1563 move(SLK_WORK, 0);
1564 clrtobot();
1565 break;
1567 case 'x':
1568 case 'q':
1569 goto done;
1571 #if HAVE_SLK_COLOR
1572 case 'F':
1573 if (has_colors()) {
1574 fg = (fg + 1) % max_colors;
1575 new_color = TRUE;
1577 break;
1578 case 'B':
1579 if (has_colors()) {
1580 bg = (bg + 1) % max_colors;
1581 new_color = TRUE;
1583 break;
1584 #endif
1586 default:
1587 beep();
1589 } while
1590 ((c = Getchar()) != EOF);
1592 done:
1593 erase();
1594 endwin();
1597 #if USE_WIDEC_SUPPORT
1598 static void
1599 wide_slk_test(void)
1600 /* exercise the soft keys */
1602 int c, fmt = 1;
1603 wchar_t buf[9];
1604 char *s;
1605 short fg = COLOR_BLACK;
1606 short bg = COLOR_WHITE;
1607 bool new_color = FALSE;
1609 c = CTRL('l');
1610 if (has_colors()) {
1611 new_color = TRUE;
1613 do {
1614 if (new_color) {
1615 init_pair(1, bg, fg);
1616 slk_color(1);
1617 new_color = FALSE;
1618 mvprintw(SLK_WORK, 0, "Colors %d/%d\n", fg, bg);
1619 refresh();
1621 move(0, 0);
1622 switch (c) {
1623 case CTRL('l'):
1624 erase();
1625 attr_on(WA_BOLD, NULL);
1626 mvaddstr(0, 20, "Soft Key Exerciser");
1627 attr_off(WA_BOLD, NULL);
1629 slk_help();
1630 /* fall through */
1632 case 'a':
1633 slk_restore();
1634 break;
1636 case 'e':
1637 wclear(stdscr);
1638 break;
1640 case 's':
1641 mvprintw(SLK_WORK, 0, "Press Q to stop the scrolling-test: ");
1642 while ((c = Getchar()) != 'Q' && (c != ERR))
1643 addch((chtype) c);
1644 break;
1646 case 'd':
1647 slk_clear();
1648 break;
1650 case 'l':
1651 fmt = 0;
1652 break;
1654 case 'c':
1655 fmt = 1;
1656 break;
1658 case 'r':
1659 fmt = 2;
1660 break;
1662 case '1':
1663 case '2':
1664 case '3':
1665 case '4':
1666 case '5':
1667 case '6':
1668 case '7':
1669 case '8':
1670 (void) mvaddstr(SLK_WORK, 0, "Please enter the label value: ");
1671 *buf = 0;
1672 if ((s = slk_label(c - '0')) != 0) {
1673 int j;
1674 for (j = 0; j < 8; ++j) {
1675 if ((buf[j] = UChar(s[j])) == 0)
1676 break;
1678 buf[j] = 0;
1680 wGet_wstring(stdscr, buf, 8);
1681 slk_wset((c - '0'), buf, fmt);
1682 slk_refresh();
1683 move(SLK_WORK, 0);
1684 clrtobot();
1685 break;
1687 case 'x':
1688 case 'q':
1689 goto done;
1691 case 'F':
1692 if (has_colors()) {
1693 fg = (fg + 1) % max_colors;
1694 new_color = TRUE;
1696 break;
1697 case 'B':
1698 if (has_colors()) {
1699 bg = (bg + 1) % max_colors;
1700 new_color = TRUE;
1702 break;
1704 default:
1705 beep();
1707 } while
1708 ((c = Getchar()) != EOF);
1710 done:
1711 erase();
1712 endwin();
1714 #endif
1716 /****************************************************************************
1718 * Alternate character-set stuff
1720 ****************************************************************************/
1722 /* ISO 6429: codes 0x80 to 0x9f may be control characters that cause the
1723 * terminal to perform functions. The remaining codes can be graphic.
1725 static void
1726 show_upper_chars(int first)
1728 bool C1 = (first == 128);
1729 int code;
1730 int last = first + 31;
1731 int reply;
1733 erase();
1734 attron(A_BOLD);
1735 mvprintw(0, 20, "Display of %s Character Codes %d to %d",
1736 C1 ? "C1" : "GR", first, last);
1737 attroff(A_BOLD);
1738 refresh();
1740 for (code = first; code <= last; code++) {
1741 int row = 4 + ((code - first) % 16);
1742 int col = ((code - first) / 16) * COLS / 2;
1743 char tmp[80];
1744 sprintf(tmp, "%3d (0x%x)", code, code);
1745 mvprintw(row, col, "%*s: ", COLS / 4, tmp);
1746 if (C1)
1747 nodelay(stdscr, TRUE);
1748 echochar(code);
1749 if (C1) {
1750 /* (yes, this _is_ crude) */
1751 while ((reply = Getchar()) != ERR) {
1752 addch(reply);
1753 napms(10);
1755 nodelay(stdscr, FALSE);
1760 static void
1761 show_box_chars(void)
1763 erase();
1764 attron(A_BOLD);
1765 mvaddstr(0, 20, "Display of the ACS Line-Drawing Set");
1766 attroff(A_BOLD);
1767 refresh();
1768 box(stdscr, 0, 0);
1769 /* *INDENT-OFF* */
1770 mvhline(LINES / 2, 0, ACS_HLINE, COLS);
1771 mvvline(0, COLS / 2, ACS_VLINE, LINES);
1772 mvaddch(0, COLS / 2, ACS_TTEE);
1773 mvaddch(LINES / 2, COLS / 2, ACS_PLUS);
1774 mvaddch(LINES - 1, COLS / 2, ACS_BTEE);
1775 mvaddch(LINES / 2, 0, ACS_LTEE);
1776 mvaddch(LINES / 2, COLS - 1, ACS_RTEE);
1777 /* *INDENT-ON* */
1781 static int
1782 show_1_acs(int n, const char *name, chtype code)
1784 const int height = 16;
1785 int row = 4 + (n % height);
1786 int col = (n / height) * COLS / 2;
1787 mvprintw(row, col, "%*s : ", COLS / 4, name);
1788 addch(code);
1789 return n + 1;
1792 static void
1793 show_acs_chars(void)
1794 /* display the ACS character set */
1796 int n;
1798 #define BOTH(name) #name, name
1800 erase();
1801 attron(A_BOLD);
1802 mvaddstr(0, 20, "Display of the ACS Character Set");
1803 attroff(A_BOLD);
1804 refresh();
1806 n = show_1_acs(0, BOTH(ACS_ULCORNER));
1807 n = show_1_acs(n, BOTH(ACS_URCORNER));
1808 n = show_1_acs(n, BOTH(ACS_LLCORNER));
1809 n = show_1_acs(n, BOTH(ACS_LRCORNER));
1811 n = show_1_acs(n, BOTH(ACS_LTEE));
1812 n = show_1_acs(n, BOTH(ACS_RTEE));
1813 n = show_1_acs(n, BOTH(ACS_TTEE));
1814 n = show_1_acs(n, BOTH(ACS_BTEE));
1816 n = show_1_acs(n, BOTH(ACS_HLINE));
1817 n = show_1_acs(n, BOTH(ACS_VLINE));
1819 n = show_1_acs(n, BOTH(ACS_LARROW));
1820 n = show_1_acs(n, BOTH(ACS_RARROW));
1821 n = show_1_acs(n, BOTH(ACS_UARROW));
1822 n = show_1_acs(n, BOTH(ACS_DARROW));
1824 n = show_1_acs(n, BOTH(ACS_BLOCK));
1825 n = show_1_acs(n, BOTH(ACS_BOARD));
1826 n = show_1_acs(n, BOTH(ACS_LANTERN));
1827 n = show_1_acs(n, BOTH(ACS_BULLET));
1828 n = show_1_acs(n, BOTH(ACS_CKBOARD));
1829 n = show_1_acs(n, BOTH(ACS_DEGREE));
1830 n = show_1_acs(n, BOTH(ACS_DIAMOND));
1831 n = show_1_acs(n, BOTH(ACS_PLMINUS));
1832 n = show_1_acs(n, BOTH(ACS_PLUS));
1834 n = show_1_acs(n, BOTH(ACS_GEQUAL));
1835 n = show_1_acs(n, BOTH(ACS_NEQUAL));
1836 n = show_1_acs(n, BOTH(ACS_LEQUAL));
1838 n = show_1_acs(n, BOTH(ACS_STERLING));
1839 n = show_1_acs(n, BOTH(ACS_PI));
1840 n = show_1_acs(n, BOTH(ACS_S1));
1841 n = show_1_acs(n, BOTH(ACS_S3));
1842 n = show_1_acs(n, BOTH(ACS_S7));
1843 n = show_1_acs(n, BOTH(ACS_S9));
1846 static void
1847 acs_display(void)
1849 int c = 'a';
1851 do {
1852 switch (c) {
1853 case 'a':
1854 show_acs_chars();
1855 break;
1856 case 'b':
1857 show_box_chars();
1858 break;
1859 case '0':
1860 case '1':
1861 case '2':
1862 case '3':
1863 show_upper_chars((c - '0') * 32 + 128);
1864 break;
1866 mvprintw(LINES - 3, 0,
1867 "Note: ANSI terminals may not display C1 characters.");
1868 mvprintw(LINES - 2, 0,
1869 "Select: a=ACS, b=box, 0=C1, 1,2,3=GR characters, q=quit");
1870 refresh();
1871 } while ((c = Getchar()) != 'x' && c != 'q');
1873 Pause();
1874 erase();
1875 endwin();
1878 #if USE_WIDEC_SUPPORT
1879 static void
1880 show_upper_widechars(int first, int repeat)
1882 cchar_t temp;
1883 wchar_t code;
1884 int last = first + 31;
1886 erase();
1887 attron(A_BOLD);
1888 mvprintw(0, 20, "Display of Character Codes %d to %d", first, last);
1889 attroff(A_BOLD);
1891 for (code = first; code <= last; code++) {
1892 int row = 4 + ((code - first) % 16);
1893 int col = ((code - first) / 16) * COLS / 2;
1894 wchar_t codes[10];
1895 attr_t attrs = A_NORMAL;
1896 char tmp[80];
1897 int count = repeat;
1899 memset(&codes, 0, sizeof(codes));
1900 codes[0] = code;
1901 sprintf(tmp, "%3ld (0x%lx)", (long) code, (long) code);
1902 mvprintw(row, col, "%*s: ", COLS / 4, tmp);
1903 setcchar(&temp, codes, attrs, 0, 0);
1904 do {
1906 * This could use add_wch(), but is done for comparison with the
1907 * normal 'f' test (and to make a test-case for echo_wchar()).
1908 * The screen will flicker because the erase() at the top of the
1909 * function is met by the builtin refresh() in echo_wchar().
1911 echo_wchar(&temp);
1912 } while (--count > 0);
1916 static int
1917 show_1_wacs(int n, const char *name, const cchar_t * code)
1919 const int height = 16;
1920 int row = 4 + (n % height);
1921 int col = (n / height) * COLS / 2;
1922 mvprintw(row, col, "%*s : ", COLS / 4, name);
1923 add_wchnstr(code, 1);
1924 return n + 1;
1927 static void
1928 show_wacs_chars(void)
1929 /* display the wide-ACS character set */
1931 int n;
1933 /*#define BOTH2(name) #name, &(name) */
1934 #define BOTH2(name) #name, name
1936 erase();
1937 attron(A_BOLD);
1938 mvaddstr(0, 20, "Display of the Wide-ACS Character Set");
1939 attroff(A_BOLD);
1940 refresh();
1942 n = show_1_wacs(0, BOTH2(WACS_ULCORNER));
1943 n = show_1_wacs(n, BOTH2(WACS_URCORNER));
1944 n = show_1_wacs(n, BOTH2(WACS_LLCORNER));
1945 n = show_1_wacs(n, BOTH2(WACS_LRCORNER));
1947 n = show_1_wacs(n, BOTH2(WACS_LTEE));
1948 n = show_1_wacs(n, BOTH2(WACS_RTEE));
1949 n = show_1_wacs(n, BOTH2(WACS_TTEE));
1950 n = show_1_wacs(n, BOTH2(WACS_BTEE));
1952 n = show_1_wacs(n, BOTH2(WACS_HLINE));
1953 n = show_1_wacs(n, BOTH2(WACS_VLINE));
1955 n = show_1_wacs(n, BOTH2(WACS_LARROW));
1956 n = show_1_wacs(n, BOTH2(WACS_RARROW));
1957 n = show_1_wacs(n, BOTH2(WACS_UARROW));
1958 n = show_1_wacs(n, BOTH2(WACS_DARROW));
1960 n = show_1_wacs(n, BOTH2(WACS_BLOCK));
1961 n = show_1_wacs(n, BOTH2(WACS_BOARD));
1962 n = show_1_wacs(n, BOTH2(WACS_LANTERN));
1963 n = show_1_wacs(n, BOTH2(WACS_BULLET));
1964 n = show_1_wacs(n, BOTH2(WACS_CKBOARD));
1965 n = show_1_wacs(n, BOTH2(WACS_DEGREE));
1966 n = show_1_wacs(n, BOTH2(WACS_DIAMOND));
1967 n = show_1_wacs(n, BOTH2(WACS_PLMINUS));
1968 n = show_1_wacs(n, BOTH2(WACS_PLUS));
1970 #ifdef CURSES_WACS_ARRAY
1971 n = show_1_wacs(n, BOTH2(WACS_GEQUAL));
1972 n = show_1_wacs(n, BOTH2(WACS_NEQUAL));
1973 n = show_1_wacs(n, BOTH2(WACS_LEQUAL));
1975 n = show_1_wacs(n, BOTH2(WACS_STERLING));
1976 n = show_1_wacs(n, BOTH2(WACS_PI));
1977 n = show_1_wacs(n, BOTH2(WACS_S1));
1978 n = show_1_wacs(n, BOTH2(WACS_S3));
1979 n = show_1_wacs(n, BOTH2(WACS_S7));
1980 n = show_1_wacs(n, BOTH2(WACS_S9));
1981 #endif
1984 static void
1985 show_wbox_chars(void)
1987 erase();
1988 attron(A_BOLD);
1989 mvaddstr(0, 20, "Display of the Wide-ACS Line-Drawing Set");
1990 attroff(A_BOLD);
1991 refresh();
1992 box_set(stdscr, 0, 0);
1993 /* *INDENT-OFF* */
1994 mvhline_set(LINES / 2, 0, WACS_HLINE, COLS);
1995 mvvline_set(0, COLS / 2, WACS_VLINE, LINES);
1996 mvadd_wch(0, COLS / 2, WACS_TTEE);
1997 mvadd_wch(LINES / 2, COLS / 2, WACS_PLUS);
1998 mvadd_wch(LINES - 1, COLS / 2, WACS_BTEE);
1999 mvadd_wch(LINES / 2, 0, WACS_LTEE);
2000 mvadd_wch(LINES / 2, COLS - 1, WACS_RTEE);
2001 /* *INDENT-ON* */
2005 static int
2006 show_2_wacs(int n, const char *name, const char *code)
2008 const int height = 16;
2009 int row = 4 + (n % height);
2010 int col = (n / height) * COLS / 2;
2011 char temp[80];
2013 mvprintw(row, col, "%*s : ", COLS / 4, name);
2014 addstr(strcpy(temp, code));
2015 return n + 1;
2018 static void
2019 show_utf8_chars(void)
2020 /* display the wide-ACS character set */
2022 int n;
2024 erase();
2025 attron(A_BOLD);
2026 mvaddstr(0, 20, "Display of the Wide-ACS Character Set");
2027 attroff(A_BOLD);
2028 refresh();
2029 /* *INDENT-OFF* */
2030 n = show_2_wacs(0, "WACS_ULCORNER", "\342\224\214");
2031 n = show_2_wacs(n, "WACS_URCORNER", "\342\224\220");
2032 n = show_2_wacs(n, "WACS_LLCORNER", "\342\224\224");
2033 n = show_2_wacs(n, "WACS_LRCORNER", "\342\224\230");
2035 n = show_2_wacs(n, "WACS_LTEE", "\342\224\234");
2036 n = show_2_wacs(n, "WACS_RTEE", "\342\224\244");
2037 n = show_2_wacs(n, "WACS_TTEE", "\342\224\254");
2038 n = show_2_wacs(n, "WACS_BTEE", "\342\224\264");
2040 n = show_2_wacs(n, "WACS_HLINE", "\342\224\200");
2041 n = show_2_wacs(n, "WACS_VLINE", "\342\224\202");
2043 n = show_2_wacs(n, "WACS_LARROW", "\342\206\220");
2044 n = show_2_wacs(n, "WACS_RARROW", "\342\206\222");
2045 n = show_2_wacs(n, "WACS_UARROW", "\342\206\221");
2046 n = show_2_wacs(n, "WACS_DARROW", "\342\206\223");
2048 n = show_2_wacs(n, "WACS_BLOCK", "\342\226\256");
2049 n = show_2_wacs(n, "WACS_BOARD", "\342\226\222");
2050 n = show_2_wacs(n, "WACS_LANTERN", "\342\230\203");
2051 n = show_2_wacs(n, "WACS_BULLET", "\302\267");
2052 n = show_2_wacs(n, "WACS_CKBOARD", "\342\226\222");
2053 n = show_2_wacs(n, "WACS_DEGREE", "\302\260");
2054 n = show_2_wacs(n, "WACS_DIAMOND", "\342\227\206");
2055 n = show_2_wacs(n, "WACS_PLMINUS", "\302\261");
2056 n = show_2_wacs(n, "WACS_PLUS", "\342\224\274");
2057 n = show_2_wacs(n, "WACS_GEQUAL", "\342\211\245");
2058 n = show_2_wacs(n, "WACS_NEQUAL", "\342\211\240");
2059 n = show_2_wacs(n, "WACS_LEQUAL", "\342\211\244");
2061 n = show_2_wacs(n, "WACS_STERLING", "\302\243");
2062 n = show_2_wacs(n, "WACS_PI", "\317\200");
2063 n = show_2_wacs(n, "WACS_S1", "\342\216\272");
2064 n = show_2_wacs(n, "WACS_S3", "\342\216\273");
2065 n = show_2_wacs(n, "WACS_S7", "\342\216\274");
2066 n = show_2_wacs(n, "WACS_S9", "\342\216\275");
2067 /* *INDENT-ON* */
2071 static void
2072 wide_acs_display(void)
2074 int c = 'a';
2075 int digit = 0;
2076 int repeat = 0;
2078 do {
2079 switch (c) {
2080 case 'a':
2081 show_wacs_chars();
2082 break;
2083 case 'b':
2084 show_wbox_chars();
2085 break;
2086 case 'u':
2087 show_utf8_chars();
2088 break;
2089 default:
2090 if (isdigit(c))
2091 digit = (c - '0');
2092 else if (c == '+')
2093 ++digit;
2094 else if (c == '-' && digit > 0)
2095 --digit;
2096 else if (c == '>')
2097 ++repeat;
2098 else if (c == '<' && repeat > 0)
2099 --repeat;
2100 else {
2101 beep();
2102 break;
2104 show_upper_widechars(digit * 32 + 128, repeat);
2105 break;
2107 mvprintw(LINES - 2, 0,
2108 "Select: a WACS, b box, u UTF-8, 0-9,+/- non-ASCII, </> repeat, q=quit");
2109 refresh();
2110 } while ((c = Getchar()) != 'x' && c != 'q');
2112 Pause();
2113 erase();
2114 endwin();
2117 #endif
2120 * Graphic-rendition test (adapted from vttest)
2122 static void
2123 test_sgr_attributes(void)
2125 int pass;
2127 for (pass = 0; pass < 2; pass++) {
2128 int normal = ((pass == 0 ? A_NORMAL : A_REVERSE)) | BLANK;
2130 /* Use non-default colors if possible to exercise bce a little */
2131 if (has_colors()) {
2132 init_pair(1, COLOR_WHITE, COLOR_BLUE);
2133 normal |= COLOR_PAIR(1);
2135 bkgdset(normal);
2136 erase();
2137 mvprintw(1, 20, "Graphic rendition test pattern:");
2139 mvprintw(4, 1, "vanilla");
2141 #define set_sgr(mask) bkgdset((normal^(mask)));
2142 set_sgr(A_BOLD);
2143 mvprintw(4, 40, "bold");
2145 set_sgr(A_UNDERLINE);
2146 mvprintw(6, 6, "underline");
2148 set_sgr(A_BOLD | A_UNDERLINE);
2149 mvprintw(6, 45, "bold underline");
2151 set_sgr(A_BLINK);
2152 mvprintw(8, 1, "blink");
2154 set_sgr(A_BLINK | A_BOLD);
2155 mvprintw(8, 40, "bold blink");
2157 set_sgr(A_UNDERLINE | A_BLINK);
2158 mvprintw(10, 6, "underline blink");
2160 set_sgr(A_BOLD | A_UNDERLINE | A_BLINK);
2161 mvprintw(10, 45, "bold underline blink");
2163 set_sgr(A_REVERSE);
2164 mvprintw(12, 1, "negative");
2166 set_sgr(A_BOLD | A_REVERSE);
2167 mvprintw(12, 40, "bold negative");
2169 set_sgr(A_UNDERLINE | A_REVERSE);
2170 mvprintw(14, 6, "underline negative");
2172 set_sgr(A_BOLD | A_UNDERLINE | A_REVERSE);
2173 mvprintw(14, 45, "bold underline negative");
2175 set_sgr(A_BLINK | A_REVERSE);
2176 mvprintw(16, 1, "blink negative");
2178 set_sgr(A_BOLD | A_BLINK | A_REVERSE);
2179 mvprintw(16, 40, "bold blink negative");
2181 set_sgr(A_UNDERLINE | A_BLINK | A_REVERSE);
2182 mvprintw(18, 6, "underline blink negative");
2184 set_sgr(A_BOLD | A_UNDERLINE | A_BLINK | A_REVERSE);
2185 mvprintw(18, 45, "bold underline blink negative");
2187 bkgdset(normal);
2188 mvprintw(LINES - 2, 1, "%s background. ", pass == 0 ? "Dark" :
2189 "Light");
2190 clrtoeol();
2191 Pause();
2194 bkgdset(A_NORMAL | BLANK);
2195 erase();
2196 endwin();
2199 /****************************************************************************
2201 * Windows and scrolling tester.
2203 ****************************************************************************/
2205 #define BOTLINES 4 /* number of line stolen from screen bottom */
2207 typedef struct {
2208 int y, x;
2209 } pair;
2211 #define FRAME struct frame
2212 FRAME
2214 FRAME *next, *last;
2215 bool do_scroll;
2216 bool do_keypad;
2217 WINDOW *wind;
2220 #ifdef NCURSES_VERSION
2221 #define keypad_active(win) (win)->_use_keypad
2222 #define scroll_active(win) (win)->_scroll
2223 #else
2224 #define keypad_active(win) FALSE
2225 #define scroll_active(win) FALSE
2226 #endif
2228 /* We need to know if these flags are actually set, so don't look in FRAME.
2229 * These names are known to work with SVr4 curses as well as ncurses. The
2230 * _use_keypad name does not work with Solaris 8.
2232 static bool
2233 HaveKeypad(FRAME * curp)
2235 WINDOW *win = (curp ? curp->wind : stdscr);
2236 return keypad_active(win);
2239 static bool
2240 HaveScroll(FRAME * curp)
2242 WINDOW *win = (curp ? curp->wind : stdscr);
2243 return scroll_active(win);
2246 static void
2247 newwin_legend(FRAME * curp)
2249 static const struct {
2250 const char *msg;
2251 int code;
2252 } legend[] = {
2254 "^C = create window", 0
2257 "^N = next window", 0
2260 "^P = previous window", 0
2263 "^F = scroll forward", 0
2266 "^B = scroll backward", 0
2269 "^K = keypad(%s)", 1
2272 "^S = scrollok(%s)", 2
2275 "^W = save window to file", 0
2278 "^R = restore window", 0
2280 #if HAVE_WRESIZE
2282 "^X = resize", 0
2284 #endif
2286 "^Q%s = exit", 3
2289 size_t n;
2290 int x;
2291 bool do_keypad = HaveKeypad(curp);
2292 bool do_scroll = HaveScroll(curp);
2293 char buf[BUFSIZ];
2295 move(LINES - 4, 0);
2296 for (n = 0; n < SIZEOF(legend); n++) {
2297 switch (legend[n].code) {
2298 default:
2299 strcpy(buf, legend[n].msg);
2300 break;
2301 case 1:
2302 sprintf(buf, legend[n].msg, do_keypad ? "yes" : "no");
2303 break;
2304 case 2:
2305 sprintf(buf, legend[n].msg, do_scroll ? "yes" : "no");
2306 break;
2307 case 3:
2308 sprintf(buf, legend[n].msg, do_keypad ? "/ESC" : "");
2309 break;
2311 x = getcurx(stdscr);
2312 addstr((COLS < (x + 3 + (int) strlen(buf))) ? "\n" : (n ? ", " : ""));
2313 addstr(buf);
2315 clrtoeol();
2318 static void
2319 transient(FRAME * curp, NCURSES_CONST char *msg)
2321 newwin_legend(curp);
2322 if (msg) {
2323 mvaddstr(LINES - 1, 0, msg);
2324 refresh();
2325 napms(1000);
2328 move(LINES - 1, 0);
2329 printw("%s characters are echoed, window should %sscroll.",
2330 HaveKeypad(curp) ? "Non-arrow" : "All other",
2331 HaveScroll(curp) ? "" : "not ");
2332 clrtoeol();
2335 static void
2336 newwin_report(FRAME * curp)
2337 /* report on the cursor's current position, then restore it */
2339 WINDOW *win = (curp != 0) ? curp->wind : stdscr;
2340 int y, x;
2342 if (win != stdscr)
2343 transient(curp, (char *) 0);
2344 getyx(win, y, x);
2345 move(LINES - 1, COLS - 17);
2346 printw("Y = %2d X = %2d", y, x);
2347 if (win != stdscr)
2348 refresh();
2349 else
2350 wmove(win, y, x);
2353 static pair *
2354 selectcell(int uli, int ulj, int lri, int lrj)
2355 /* arrows keys move cursor, return location at current on non-arrow key */
2357 static pair res; /* result cell */
2358 int si = lri - uli + 1; /* depth of the select area */
2359 int sj = lrj - ulj + 1; /* width of the select area */
2360 int i = 0, j = 0; /* offsets into the select area */
2362 res.y = uli;
2363 res.x = ulj;
2364 for (;;) {
2365 move(uli + i, ulj + j);
2366 newwin_report((FRAME *) 0);
2368 switch (Getchar()) {
2369 case KEY_UP:
2370 i += si - 1;
2371 break;
2372 case KEY_DOWN:
2373 i++;
2374 break;
2375 case KEY_LEFT:
2376 j += sj - 1;
2377 break;
2378 case KEY_RIGHT:
2379 j++;
2380 break;
2381 case QUIT:
2382 case ESCAPE:
2383 return ((pair *) 0);
2384 #ifdef NCURSES_MOUSE_VERSION
2385 case KEY_MOUSE:
2387 MEVENT event;
2389 getmouse(&event);
2390 if (event.y > uli && event.x > ulj) {
2391 i = event.y - uli;
2392 j = event.x - ulj;
2393 } else {
2394 beep();
2395 break;
2398 /* FALLTHRU */
2399 #endif
2400 default:
2401 res.y = uli + i;
2402 res.x = ulj + j;
2403 return (&res);
2405 i %= si;
2406 j %= sj;
2410 static void
2411 outerbox(pair ul, pair lr, bool onoff)
2412 /* draw or erase a box *outside* the given pair of corners */
2414 mvaddch(ul.y - 1, lr.x - 1, onoff ? ACS_ULCORNER : ' ');
2415 mvaddch(ul.y - 1, lr.x + 1, onoff ? ACS_URCORNER : ' ');
2416 mvaddch(lr.y + 1, lr.x + 1, onoff ? ACS_LRCORNER : ' ');
2417 mvaddch(lr.y + 1, ul.x - 1, onoff ? ACS_LLCORNER : ' ');
2418 move(ul.y - 1, ul.x);
2419 hline(onoff ? ACS_HLINE : ' ', lr.x - ul.x + 1);
2420 move(ul.y, ul.x - 1);
2421 vline(onoff ? ACS_VLINE : ' ', lr.y - ul.y + 1);
2422 move(lr.y + 1, ul.x);
2423 hline(onoff ? ACS_HLINE : ' ', lr.x - ul.x + 1);
2424 move(ul.y, lr.x + 1);
2425 vline(onoff ? ACS_VLINE : ' ', lr.y - ul.y + 1);
2428 static WINDOW *
2429 getwindow(void)
2430 /* Ask user for a window definition */
2432 WINDOW *rwindow;
2433 pair ul, lr, *tmp;
2435 move(0, 0);
2436 clrtoeol();
2437 addstr("Use arrows to move cursor, anything else to mark corner 1");
2438 refresh();
2439 if ((tmp = selectcell(2, 1, LINES - BOTLINES - 2, COLS - 2)) == (pair *) 0)
2440 return ((WINDOW *) 0);
2441 memcpy(&ul, tmp, sizeof(pair));
2442 mvaddch(ul.y - 1, ul.x - 1, ACS_ULCORNER);
2443 move(0, 0);
2444 clrtoeol();
2445 addstr("Use arrows to move cursor, anything else to mark corner 2");
2446 refresh();
2447 if ((tmp = selectcell(ul.y, ul.x, LINES - BOTLINES - 2, COLS - 2)) ==
2448 (pair *) 0)
2449 return ((WINDOW *) 0);
2450 memcpy(&lr, tmp, sizeof(pair));
2452 rwindow = subwin(stdscr, lr.y - ul.y + 1, lr.x - ul.x + 1, ul.y, ul.x);
2454 outerbox(ul, lr, TRUE);
2455 refresh();
2457 wrefresh(rwindow);
2459 move(0, 0);
2460 clrtoeol();
2461 return (rwindow);
2464 static void
2465 newwin_move(FRAME * curp, int dy, int dx)
2467 WINDOW *win = (curp != 0) ? curp->wind : stdscr;
2468 int cur_y, cur_x;
2469 int max_y, max_x;
2471 getyx(win, cur_y, cur_x);
2472 getmaxyx(win, max_y, max_x);
2473 if ((cur_x += dx) < 0)
2474 cur_x = 0;
2475 else if (cur_x >= max_x)
2476 cur_x = max_x - 1;
2477 if ((cur_y += dy) < 0)
2478 cur_y = 0;
2479 else if (cur_y >= max_y)
2480 cur_y = max_y - 1;
2481 wmove(win, cur_y, cur_x);
2484 static FRAME *
2485 delete_framed(FRAME * fp, bool showit)
2487 FRAME *np;
2489 fp->last->next = fp->next;
2490 fp->next->last = fp->last;
2492 if (showit) {
2493 werase(fp->wind);
2494 wrefresh(fp->wind);
2496 delwin(fp->wind);
2498 np = (fp == fp->next) ? 0 : fp->next;
2499 free(fp);
2500 return np;
2503 static void
2504 acs_and_scroll(void)
2505 /* Demonstrate windows */
2507 int c, i;
2508 FILE *fp;
2509 FRAME *current = (FRAME *) 0, *neww;
2510 WINDOW *usescr = stdscr;
2512 #define DUMPFILE "screendump"
2514 #ifdef NCURSES_MOUSE_VERSION
2515 mousemask(BUTTON1_CLICKED, (mmask_t *) 0);
2516 #endif
2517 c = CTRL('C');
2518 raw();
2519 do {
2520 transient((FRAME *) 0, (char *) 0);
2521 switch (c) {
2522 case CTRL('C'):
2523 neww = (FRAME *) calloc(1, sizeof(FRAME));
2524 if ((neww->wind = getwindow()) == (WINDOW *) 0)
2525 goto breakout;
2527 if (current == 0) { /* First element, */
2528 neww->next = neww; /* so point it at itself */
2529 neww->last = neww;
2530 } else {
2531 neww->next = current->next;
2532 neww->last = current;
2533 neww->last->next = neww;
2534 neww->next->last = neww;
2536 current = neww;
2537 /* SVr4 curses sets the keypad on all newly-created windows to
2538 * false. Someone reported that PDCurses makes new windows inherit
2539 * this flag. Remove the following 'keypad()' call to test this
2541 keypad(current->wind, TRUE);
2542 current->do_keypad = HaveKeypad(current);
2543 current->do_scroll = HaveScroll(current);
2544 break;
2546 case CTRL('N'): /* go to next window */
2547 if (current)
2548 current = current->next;
2549 break;
2551 case CTRL('P'): /* go to previous window */
2552 if (current)
2553 current = current->last;
2554 break;
2556 case CTRL('F'): /* scroll current window forward */
2557 if (current)
2558 wscrl(current->wind, 1);
2559 break;
2561 case CTRL('B'): /* scroll current window backwards */
2562 if (current)
2563 wscrl(current->wind, -1);
2564 break;
2566 case CTRL('K'): /* toggle keypad mode for current */
2567 if (current) {
2568 current->do_keypad = !current->do_keypad;
2569 keypad(current->wind, current->do_keypad);
2571 break;
2573 case CTRL('S'):
2574 if (current) {
2575 current->do_scroll = !current->do_scroll;
2576 scrollok(current->wind, current->do_scroll);
2578 break;
2580 case CTRL('W'): /* save and delete window */
2581 if (current == current->next) {
2582 transient(current, "Will not save/delete ONLY window");
2583 break;
2584 } else if ((fp = fopen(DUMPFILE, "w")) == (FILE *) 0) {
2585 transient(current, "Can't open screen dump file");
2586 } else {
2587 (void) putwin(current->wind, fp);
2588 (void) fclose(fp);
2590 current = delete_framed(current, TRUE);
2592 break;
2594 case CTRL('R'): /* restore window */
2595 if ((fp = fopen(DUMPFILE, "r")) == (FILE *) 0) {
2596 transient(current, "Can't open screen dump file");
2597 } else {
2598 neww = (FRAME *) calloc(1, sizeof(FRAME));
2600 neww->next = current->next;
2601 neww->last = current;
2602 neww->last->next = neww;
2603 neww->next->last = neww;
2605 neww->wind = getwin(fp);
2606 (void) fclose(fp);
2608 wrefresh(neww->wind);
2610 break;
2612 #if HAVE_WRESIZE
2613 case CTRL('X'): /* resize window */
2614 if (current) {
2615 pair *tmp, ul, lr;
2616 int mx, my;
2618 move(0, 0);
2619 clrtoeol();
2620 addstr("Use arrows to move cursor, anything else to mark new corner");
2621 refresh();
2623 getbegyx(current->wind, ul.y, ul.x);
2625 tmp = selectcell(ul.y, ul.x, LINES - BOTLINES - 2, COLS - 2);
2626 if (tmp == (pair *) 0) {
2627 beep();
2628 break;
2631 getmaxyx(current->wind, lr.y, lr.x);
2632 lr.y += (ul.y - 1);
2633 lr.x += (ul.x - 1);
2634 outerbox(ul, lr, FALSE);
2635 wnoutrefresh(stdscr);
2637 /* strictly cosmetic hack for the test */
2638 getmaxyx(current->wind, my, mx);
2639 if (my > tmp->y - ul.y) {
2640 getyx(current->wind, lr.y, lr.x);
2641 wmove(current->wind, tmp->y - ul.y + 1, 0);
2642 wclrtobot(current->wind);
2643 wmove(current->wind, lr.y, lr.x);
2645 if (mx > tmp->x - ul.x)
2646 for (i = 0; i < my; i++) {
2647 wmove(current->wind, i, tmp->x - ul.x + 1);
2648 wclrtoeol(current->wind);
2650 wnoutrefresh(current->wind);
2652 memcpy(&lr, tmp, sizeof(pair));
2653 (void) wresize(current->wind, lr.y - ul.y + 0, lr.x - ul.x + 0);
2655 getbegyx(current->wind, ul.y, ul.x);
2656 getmaxyx(current->wind, lr.y, lr.x);
2657 lr.y += (ul.y - 1);
2658 lr.x += (ul.x - 1);
2659 outerbox(ul, lr, TRUE);
2660 wnoutrefresh(stdscr);
2662 wnoutrefresh(current->wind);
2663 move(0, 0);
2664 clrtoeol();
2665 doupdate();
2667 break;
2668 #endif /* HAVE_WRESIZE */
2670 case KEY_F(10): /* undocumented --- use this to test area clears */
2671 selectcell(0, 0, LINES - 1, COLS - 1);
2672 clrtobot();
2673 refresh();
2674 break;
2676 case KEY_UP:
2677 newwin_move(current, -1, 0);
2678 break;
2679 case KEY_DOWN:
2680 newwin_move(current, 1, 0);
2681 break;
2682 case KEY_LEFT:
2683 newwin_move(current, 0, -1);
2684 break;
2685 case KEY_RIGHT:
2686 newwin_move(current, 0, 1);
2687 break;
2689 case KEY_BACKSPACE:
2690 /* FALLTHROUGH */
2691 case KEY_DC:
2693 int y, x;
2694 getyx(current->wind, y, x);
2695 if (--x < 0) {
2696 if (--y < 0)
2697 break;
2698 x = getmaxx(current->wind) - 1;
2700 mvwdelch(current->wind, y, x);
2702 break;
2704 case '\r':
2705 c = '\n';
2706 /* FALLTHROUGH */
2708 default:
2709 if (current)
2710 waddch(current->wind, (chtype) c);
2711 else
2712 beep();
2713 break;
2715 newwin_report(current);
2716 usescr = (current ? current->wind : stdscr);
2717 wrefresh(usescr);
2718 } while
2719 ((c = wGetchar(usescr)) != QUIT
2720 && !((c == ESCAPE) && (keypad_active(usescr)))
2721 && (c != ERR));
2723 breakout:
2724 while (current != 0)
2725 current = delete_framed(current, FALSE);
2727 scrollok(stdscr, TRUE); /* reset to driver's default */
2728 #ifdef NCURSES_MOUSE_VERSION
2729 mousemask(0, (mmask_t *) 0);
2730 #endif
2731 noraw();
2732 erase();
2733 endwin();
2736 /****************************************************************************
2738 * Panels tester
2740 ****************************************************************************/
2742 #if USE_LIBPANEL
2743 static unsigned long nap_msec = 1;
2745 static NCURSES_CONST char *mod[] =
2747 "test ",
2748 "TEST ",
2749 "(**) ",
2750 "*()* ",
2751 "<--> ",
2752 "LAST "
2755 /*+-------------------------------------------------------------------------
2756 wait_a_while(msec)
2757 --------------------------------------------------------------------------*/
2758 static void
2759 wait_a_while(unsigned long msec GCC_UNUSED)
2761 #if HAVE_NAPMS
2762 if (nap_msec == 1)
2763 wGetchar(stdscr);
2764 else
2765 napms(nap_msec);
2766 #else
2767 if (nap_msec == 1)
2768 wGetchar(stdscr);
2769 else if (msec > 1000L)
2770 sleep((int) msec / 1000L);
2771 else
2772 sleep(1);
2773 #endif
2774 } /* end of wait_a_while */
2776 /*+-------------------------------------------------------------------------
2777 saywhat(text)
2778 --------------------------------------------------------------------------*/
2779 static void
2780 saywhat(NCURSES_CONST char *text)
2782 wmove(stdscr, LINES - 1, 0);
2783 wclrtoeol(stdscr);
2784 waddstr(stdscr, text);
2785 } /* end of saywhat */
2787 /*+-------------------------------------------------------------------------
2788 mkpanel(rows,cols,tly,tlx) - alloc a win and panel and associate them
2789 --------------------------------------------------------------------------*/
2790 static PANEL *
2791 mkpanel(int color, int rows, int cols, int tly, int tlx)
2793 WINDOW *win;
2794 PANEL *pan = 0;
2796 if ((win = newwin(rows, cols, tly, tlx)) != 0) {
2797 if ((pan = new_panel(win)) == 0) {
2798 delwin(win);
2799 } else if (has_colors()) {
2800 int fg = (color == COLOR_BLUE) ? COLOR_WHITE : COLOR_BLACK;
2801 int bg = color;
2802 init_pair(color, fg, bg);
2803 wbkgdset(win, COLOR_PAIR(color) | ' ');
2804 } else {
2805 wbkgdset(win, A_BOLD | ' ');
2808 return pan;
2809 } /* end of mkpanel */
2811 /*+-------------------------------------------------------------------------
2812 rmpanel(pan)
2813 --------------------------------------------------------------------------*/
2814 static void
2815 rmpanel(PANEL * pan)
2817 WINDOW *win = panel_window(pan);
2818 del_panel(pan);
2819 delwin(win);
2820 } /* end of rmpanel */
2822 /*+-------------------------------------------------------------------------
2823 pflush()
2824 --------------------------------------------------------------------------*/
2825 static void
2826 pflush(void)
2828 update_panels();
2829 doupdate();
2830 } /* end of pflush */
2832 /*+-------------------------------------------------------------------------
2833 fill_panel(win)
2834 --------------------------------------------------------------------------*/
2835 static void
2836 fill_panel(PANEL * pan)
2838 WINDOW *win = panel_window(pan);
2839 int num = ((const char *) panel_userptr(pan))[1];
2840 int y, x;
2842 wmove(win, 1, 1);
2843 wprintw(win, "-pan%c-", num);
2844 wclrtoeol(win);
2845 box(win, 0, 0);
2846 for (y = 2; y < getmaxy(win) - 1; y++) {
2847 for (x = 1; x < getmaxx(win) - 1; x++) {
2848 wmove(win, y, x);
2849 waddch(win, num);
2852 } /* end of fill_panel */
2854 static void
2855 demo_panels(void)
2857 int itmp;
2858 register int y, x;
2860 refresh();
2862 for (y = 0; y < LINES - 1; y++) {
2863 for (x = 0; x < COLS; x++)
2864 wprintw(stdscr, "%d", (y + x) % 10);
2866 for (y = 0; y < 5; y++) {
2867 PANEL *p1;
2868 PANEL *p2;
2869 PANEL *p3;
2870 PANEL *p4;
2871 PANEL *p5;
2873 p1 = mkpanel(COLOR_RED,
2874 LINES / 2 - 2,
2875 COLS / 8 + 1,
2878 set_panel_userptr(p1, (NCURSES_CONST void *) "p1");
2880 p2 = mkpanel(COLOR_GREEN,
2881 LINES / 2 + 1,
2882 COLS / 7,
2883 LINES / 4,
2884 COLS / 10);
2885 set_panel_userptr(p2, (NCURSES_CONST void *) "p2");
2887 p3 = mkpanel(COLOR_YELLOW,
2888 LINES / 4,
2889 COLS / 10,
2890 LINES / 2,
2891 COLS / 9);
2892 set_panel_userptr(p3, (NCURSES_CONST void *) "p3");
2894 p4 = mkpanel(COLOR_BLUE,
2895 LINES / 2 - 2,
2896 COLS / 8,
2897 LINES / 2 - 2,
2898 COLS / 3);
2899 set_panel_userptr(p4, (NCURSES_CONST void *) "p4");
2901 p5 = mkpanel(COLOR_MAGENTA,
2902 LINES / 2 - 2,
2903 COLS / 8,
2904 LINES / 2,
2905 COLS / 2 - 2);
2906 set_panel_userptr(p5, (NCURSES_CONST void *) "p5");
2908 fill_panel(p1);
2909 fill_panel(p2);
2910 fill_panel(p3);
2911 fill_panel(p4);
2912 fill_panel(p5);
2913 hide_panel(p4);
2914 hide_panel(p5);
2915 pflush();
2916 saywhat("press any key to continue");
2917 wait_a_while(nap_msec);
2919 saywhat("h3 s1 s2 s4 s5; press any key to continue");
2920 move_panel(p1, 0, 0);
2921 hide_panel(p3);
2922 show_panel(p1);
2923 show_panel(p2);
2924 show_panel(p4);
2925 show_panel(p5);
2926 pflush();
2927 wait_a_while(nap_msec);
2929 saywhat("s1; press any key to continue");
2930 show_panel(p1);
2931 pflush();
2932 wait_a_while(nap_msec);
2934 saywhat("s2; press any key to continue");
2935 show_panel(p2);
2936 pflush();
2937 wait_a_while(nap_msec);
2939 saywhat("m2; press any key to continue");
2940 move_panel(p2, LINES / 3 + 1, COLS / 8);
2941 pflush();
2942 wait_a_while(nap_msec);
2944 saywhat("s3;");
2945 show_panel(p3);
2946 pflush();
2947 wait_a_while(nap_msec);
2949 saywhat("m3; press any key to continue");
2950 move_panel(p3, LINES / 4 + 1, COLS / 15);
2951 pflush();
2952 wait_a_while(nap_msec);
2954 saywhat("b3; press any key to continue");
2955 bottom_panel(p3);
2956 pflush();
2957 wait_a_while(nap_msec);
2959 saywhat("s4; press any key to continue");
2960 show_panel(p4);
2961 pflush();
2962 wait_a_while(nap_msec);
2964 saywhat("s5; press any key to continue");
2965 show_panel(p5);
2966 pflush();
2967 wait_a_while(nap_msec);
2969 saywhat("t3; press any key to continue");
2970 top_panel(p3);
2971 pflush();
2972 wait_a_while(nap_msec);
2974 saywhat("t1; press any key to continue");
2975 top_panel(p1);
2976 pflush();
2977 wait_a_while(nap_msec);
2979 saywhat("t2; press any key to continue");
2980 top_panel(p2);
2981 pflush();
2982 wait_a_while(nap_msec);
2984 saywhat("t3; press any key to continue");
2985 top_panel(p3);
2986 pflush();
2987 wait_a_while(nap_msec);
2989 saywhat("t4; press any key to continue");
2990 top_panel(p4);
2991 pflush();
2992 wait_a_while(nap_msec);
2994 for (itmp = 0; itmp < 6; itmp++) {
2995 WINDOW *w4 = panel_window(p4);
2996 WINDOW *w5 = panel_window(p5);
2998 saywhat("m4; press any key to continue");
2999 wmove(w4, LINES / 8, 1);
3000 waddstr(w4, mod[itmp]);
3001 move_panel(p4, LINES / 6, itmp * (COLS / 8));
3002 wmove(w5, LINES / 6, 1);
3003 waddstr(w5, mod[itmp]);
3004 pflush();
3005 wait_a_while(nap_msec);
3007 saywhat("m5; press any key to continue");
3008 wmove(w4, LINES / 6, 1);
3009 waddstr(w4, mod[itmp]);
3010 move_panel(p5, LINES / 3 - 1, (itmp * 10) + 6);
3011 wmove(w5, LINES / 8, 1);
3012 waddstr(w5, mod[itmp]);
3013 pflush();
3014 wait_a_while(nap_msec);
3017 saywhat("m4; press any key to continue");
3018 move_panel(p4, LINES / 6, itmp * (COLS / 8));
3019 pflush();
3020 wait_a_while(nap_msec);
3022 saywhat("t5; press any key to continue");
3023 top_panel(p5);
3024 pflush();
3025 wait_a_while(nap_msec);
3027 saywhat("t2; press any key to continue");
3028 top_panel(p2);
3029 pflush();
3030 wait_a_while(nap_msec);
3032 saywhat("t1; press any key to continue");
3033 top_panel(p1);
3034 pflush();
3035 wait_a_while(nap_msec);
3037 saywhat("d2; press any key to continue");
3038 rmpanel(p2);
3039 pflush();
3040 wait_a_while(nap_msec);
3042 saywhat("h3; press any key to continue");
3043 hide_panel(p3);
3044 pflush();
3045 wait_a_while(nap_msec);
3047 saywhat("d1; press any key to continue");
3048 rmpanel(p1);
3049 pflush();
3050 wait_a_while(nap_msec);
3052 saywhat("d4; press any key to continue");
3053 rmpanel(p4);
3054 pflush();
3055 wait_a_while(nap_msec);
3057 saywhat("d5; press any key to continue");
3058 rmpanel(p5);
3059 pflush();
3060 wait_a_while(nap_msec);
3061 if (nap_msec == 1)
3062 break;
3063 nap_msec = 100L;
3066 erase();
3067 endwin();
3070 /****************************************************************************
3072 * Pad tester
3074 ****************************************************************************/
3076 #define GRIDSIZE 3
3078 static bool pending_pan = FALSE;
3079 static bool show_panner_legend = TRUE;
3081 static int
3082 panner_legend(int line)
3084 static const char *const legend[] =
3086 "Use arrow keys (or U,D,L,R) to pan, q to quit, ! to shell-out.",
3087 "Use +,- (or j,k) to grow/shrink the panner vertically.",
3088 "Use <,> (or h,l) to grow/shrink the panner horizontally.",
3089 "Number repeats. Toggle legend:?, timer:t, scroll mark:s."
3091 int n = (SIZEOF(legend) - (LINES - line));
3092 if (line < LINES && (n >= 0)) {
3093 move(line, 0);
3094 if (show_panner_legend)
3095 printw("%s", legend[n]);
3096 clrtoeol();
3097 return show_panner_legend;
3099 return FALSE;
3102 static void
3103 panner_h_cleanup(int from_y, int from_x, int to_x)
3105 if (!panner_legend(from_y))
3106 do_h_line(from_y, from_x, ' ', to_x);
3109 static void
3110 panner_v_cleanup(int from_y, int from_x, int to_y)
3112 if (!panner_legend(from_y))
3113 do_v_line(from_y, from_x, ' ', to_y);
3116 static void
3117 panner(WINDOW *pad,
3118 int top_x, int top_y, int porty, int portx,
3119 int (*pgetc) (WINDOW *))
3121 #if HAVE_GETTIMEOFDAY
3122 struct timeval before, after;
3123 bool timing = TRUE;
3124 #endif
3125 bool scrollers = TRUE;
3126 int basex = 0;
3127 int basey = 0;
3128 int pxmax, pymax, lowend, highend, c;
3130 getmaxyx(pad, pymax, pxmax);
3131 scrollok(stdscr, FALSE); /* we don't want stdscr to scroll! */
3133 c = KEY_REFRESH;
3134 do {
3135 #ifdef NCURSES_VERSION
3137 * During shell-out, the user may have resized the window. Adjust
3138 * the port size of the pad to accommodate this. Ncurses automatically
3139 * resizes all of the normal windows to fit on the new screen.
3141 if (top_x > COLS)
3142 top_x = COLS;
3143 if (portx > COLS)
3144 portx = COLS;
3145 if (top_y > LINES)
3146 top_y = LINES;
3147 if (porty > LINES)
3148 porty = LINES;
3149 #endif
3150 switch (c) {
3151 case KEY_REFRESH:
3152 erase();
3154 /* FALLTHRU */
3155 case '?':
3156 if (c == '?')
3157 show_panner_legend = !show_panner_legend;
3158 panner_legend(LINES - 4);
3159 panner_legend(LINES - 3);
3160 panner_legend(LINES - 2);
3161 panner_legend(LINES - 1);
3162 break;
3163 #if HAVE_GETTIMEOFDAY
3164 case 't':
3165 timing = !timing;
3166 if (!timing)
3167 panner_legend(LINES - 1);
3168 break;
3169 #endif
3170 case 's':
3171 scrollers = !scrollers;
3172 break;
3174 /* Move the top-left corner of the pad, keeping the bottom-right
3175 * corner fixed.
3177 case 'h': /* increase-columns: move left edge to left */
3178 if (top_x <= 0)
3179 beep();
3180 else {
3181 panner_v_cleanup(top_y, top_x, porty);
3182 top_x--;
3184 break;
3186 case 'j': /* decrease-lines: move top-edge down */
3187 if (top_y >= porty)
3188 beep();
3189 else {
3190 panner_h_cleanup(top_y - 1, top_x - (top_x > 0), portx);
3191 top_y++;
3193 break;
3195 case 'k': /* increase-lines: move top-edge up */
3196 if (top_y <= 0)
3197 beep();
3198 else {
3199 top_y--;
3200 panner_h_cleanup(top_y, top_x, portx);
3202 break;
3204 case 'l': /* decrease-columns: move left-edge to right */
3205 if (top_x >= portx)
3206 beep();
3207 else {
3208 panner_v_cleanup(top_y - (top_y > 0), top_x - 1, porty);
3209 top_x++;
3211 break;
3213 /* Move the bottom-right corner of the pad, keeping the top-left
3214 * corner fixed.
3216 case KEY_IC: /* increase-columns: move right-edge to right */
3217 if (portx >= pxmax || portx >= COLS)
3218 beep();
3219 else {
3220 panner_v_cleanup(top_y - (top_y > 0), portx - 1, porty);
3221 ++portx;
3223 break;
3225 case KEY_IL: /* increase-lines: move bottom-edge down */
3226 if (porty >= pymax || porty >= LINES)
3227 beep();
3228 else {
3229 panner_h_cleanup(porty - 1, top_x - (top_x > 0), portx);
3230 ++porty;
3232 break;
3234 case KEY_DC: /* decrease-columns: move bottom edge up */
3235 if (portx <= top_x)
3236 beep();
3237 else {
3238 portx--;
3239 panner_v_cleanup(top_y - (top_y > 0), portx, porty);
3241 break;
3243 case KEY_DL: /* decrease-lines */
3244 if (porty <= top_y)
3245 beep();
3246 else {
3247 porty--;
3248 panner_h_cleanup(porty, top_x - (top_x > 0), portx);
3250 break;
3252 case KEY_LEFT: /* pan leftwards */
3253 if (basex > 0)
3254 basex--;
3255 else
3256 beep();
3257 break;
3259 case KEY_RIGHT: /* pan rightwards */
3260 if (basex + portx - (pymax > porty) < pxmax)
3261 basex++;
3262 else
3263 beep();
3264 break;
3266 case KEY_UP: /* pan upwards */
3267 if (basey > 0)
3268 basey--;
3269 else
3270 beep();
3271 break;
3273 case KEY_DOWN: /* pan downwards */
3274 if (basey + porty - (pxmax > portx) < pymax)
3275 basey++;
3276 else
3277 beep();
3278 break;
3280 case 'H':
3281 case KEY_HOME:
3282 case KEY_FIND:
3283 basey = 0;
3284 break;
3286 case 'E':
3287 case KEY_END:
3288 case KEY_SELECT:
3289 basey = pymax - porty;
3290 if (basey < 0)
3291 basey = 0;
3292 break;
3294 default:
3295 beep();
3296 break;
3299 mvaddch(top_y - 1, top_x - 1, ACS_ULCORNER);
3300 do_v_line(top_y, top_x - 1, ACS_VLINE, porty);
3301 do_h_line(top_y - 1, top_x, ACS_HLINE, portx);
3303 if (scrollers && (pxmax > portx - 1)) {
3304 int length = (portx - top_x - 1);
3305 float ratio = ((float) length) / ((float) pxmax);
3307 lowend = (int) (top_x + (basex * ratio));
3308 highend = (int) (top_x + ((basex + length) * ratio));
3310 do_h_line(porty - 1, top_x, ACS_HLINE, lowend);
3311 if (highend < portx) {
3312 attron(A_REVERSE);
3313 do_h_line(porty - 1, lowend, ' ', highend + 1);
3314 attroff(A_REVERSE);
3315 do_h_line(porty - 1, highend + 1, ACS_HLINE, portx);
3317 } else
3318 do_h_line(porty - 1, top_x, ACS_HLINE, portx);
3320 if (scrollers && (pymax > porty - 1)) {
3321 int length = (porty - top_y - 1);
3322 float ratio = ((float) length) / ((float) pymax);
3324 lowend = (int) (top_y + (basey * ratio));
3325 highend = (int) (top_y + ((basey + length) * ratio));
3327 do_v_line(top_y, portx - 1, ACS_VLINE, lowend);
3328 if (highend < porty) {
3329 attron(A_REVERSE);
3330 do_v_line(lowend, portx - 1, ' ', highend + 1);
3331 attroff(A_REVERSE);
3332 do_v_line(highend + 1, portx - 1, ACS_VLINE, porty);
3334 } else
3335 do_v_line(top_y, portx - 1, ACS_VLINE, porty);
3337 mvaddch(top_y - 1, portx - 1, ACS_URCORNER);
3338 mvaddch(porty - 1, top_x - 1, ACS_LLCORNER);
3339 mvaddch(porty - 1, portx - 1, ACS_LRCORNER);
3341 if (!pending_pan) {
3342 #if HAVE_GETTIMEOFDAY
3343 gettimeofday(&before, 0);
3344 #endif
3345 wnoutrefresh(stdscr);
3347 pnoutrefresh(pad,
3348 basey, basex,
3349 top_y, top_x,
3350 porty - (pxmax > portx) - 1,
3351 portx - (pymax > porty) - 1);
3353 doupdate();
3354 #if HAVE_GETTIMEOFDAY
3355 if (timing) {
3356 double elapsed;
3357 gettimeofday(&after, 0);
3358 elapsed = (after.tv_sec + after.tv_usec / 1.0e6)
3359 - (before.tv_sec + before.tv_usec / 1.0e6);
3360 move(LINES - 1, COLS - 20);
3361 printw("Secs: %2.03f", elapsed);
3362 refresh();
3364 #endif
3367 } while
3368 ((c = pgetc(pad)) != KEY_EXIT);
3370 scrollok(stdscr, TRUE); /* reset to driver's default */
3373 static int
3374 padgetch(WINDOW *win)
3376 static int count;
3377 static int last;
3378 int c;
3380 if ((pending_pan = (count > 0)) != FALSE) {
3381 count--;
3382 pending_pan = (count != 0);
3383 } else {
3384 for (;;) {
3385 switch (c = wGetchar(win)) {
3386 case '!':
3387 ShellOut(FALSE);
3388 /* FALLTHRU */
3389 case CTRL('r'):
3390 endwin();
3391 refresh();
3392 c = KEY_REFRESH;
3393 break;
3394 case CTRL('l'):
3395 c = KEY_REFRESH;
3396 break;
3397 case 'U':
3398 c = KEY_UP;
3399 break;
3400 case 'D':
3401 c = KEY_DOWN;
3402 break;
3403 case 'R':
3404 c = KEY_RIGHT;
3405 break;
3406 case 'L':
3407 c = KEY_LEFT;
3408 break;
3409 case '+':
3410 c = KEY_IL;
3411 break;
3412 case '-':
3413 c = KEY_DL;
3414 break;
3415 case '>':
3416 c = KEY_IC;
3417 break;
3418 case '<':
3419 c = KEY_DC;
3420 break;
3421 case ERR: /* FALLTHRU */
3422 case 'q':
3423 count = 0;
3424 c = KEY_EXIT;
3425 break;
3426 default:
3427 if (c >= '0' && c <= '9') {
3428 count = count * 10 + (c - '0');
3429 continue;
3431 break;
3433 last = c;
3434 break;
3436 if (count > 0)
3437 count--;
3439 return (last);
3442 #define PAD_HIGH 200
3443 #define PAD_WIDE 200
3445 static void
3446 demo_pad(void)
3447 /* Demonstrate pads. */
3449 int i, j;
3450 unsigned gridcount = 0;
3451 WINDOW *panpad = newpad(PAD_HIGH, PAD_WIDE);
3453 if (panpad == 0) {
3454 Cannot("cannot create requested pad");
3455 return;
3458 for (i = 0; i < PAD_HIGH; i++) {
3459 for (j = 0; j < PAD_WIDE; j++)
3460 if (i % GRIDSIZE == 0 && j % GRIDSIZE == 0) {
3461 if (i == 0 || j == 0)
3462 waddch(panpad, '+');
3463 else
3464 waddch(panpad, (chtype) ('A' + (gridcount++ % 26)));
3465 } else if (i % GRIDSIZE == 0)
3466 waddch(panpad, '-');
3467 else if (j % GRIDSIZE == 0)
3468 waddch(panpad, '|');
3469 else
3470 waddch(panpad, ' ');
3472 panner_legend(LINES - 4);
3473 panner_legend(LINES - 3);
3474 panner_legend(LINES - 2);
3475 panner_legend(LINES - 1);
3477 keypad(panpad, TRUE);
3479 /* Make the pad (initially) narrow enough that a trace file won't wrap.
3480 * We'll still be able to widen it during a test, since that's required
3481 * for testing boundaries.
3483 panner(panpad, 2, 2, LINES - 5, COLS - 15, padgetch);
3485 delwin(panpad);
3486 endwin();
3487 erase();
3489 #endif /* USE_LIBPANEL */
3491 /****************************************************************************
3493 * Tests from John Burnell's PDCurses tester
3495 ****************************************************************************/
3497 static void
3498 Continue(WINDOW *win)
3500 noecho();
3501 wmove(win, 10, 1);
3502 mvwaddstr(win, 10, 1, " Press any key to continue");
3503 wrefresh(win);
3504 wGetchar(win);
3507 static void
3508 flushinp_test(WINDOW *win)
3509 /* Input test, adapted from John Burnell's PDCurses tester */
3511 int w, h, bx, by, sw, sh, i;
3513 WINDOW *subWin;
3514 wclear(win);
3516 getmaxyx(win, h, w);
3517 getbegyx(win, by, bx);
3518 sw = w / 3;
3519 sh = h / 3;
3520 if ((subWin = subwin(win, sh, sw, by + h - sh - 2, bx + w - sw - 2)) == 0)
3521 return;
3523 #ifdef A_COLOR
3524 if (has_colors()) {
3525 init_pair(2, COLOR_CYAN, COLOR_BLUE);
3526 wbkgd(subWin, COLOR_PAIR(2) | ' ');
3528 #endif
3529 wattrset(subWin, A_BOLD);
3530 box(subWin, ACS_VLINE, ACS_HLINE);
3531 mvwaddstr(subWin, 2, 1, "This is a subwindow");
3532 wrefresh(win);
3535 * This used to set 'nocbreak()'. However, Alexander Lukyanov says that
3536 * it only happened to "work" on SVr4 because that implementation does not
3537 * emulate nocbreak+noecho mode, whereas ncurses does. To get the desired
3538 * test behavior, we're using 'cbreak()', which will allow a single
3539 * character to return without needing a newline. - T.Dickey 1997/10/11.
3541 cbreak();
3542 mvwaddstr(win, 0, 1, "This is a test of the flushinp() call.");
3544 mvwaddstr(win, 2, 1, "Type random keys for 5 seconds.");
3545 mvwaddstr(win, 3, 1,
3546 "These should be discarded (not echoed) after the subwindow goes away.");
3547 wrefresh(win);
3549 for (i = 0; i < 5; i++) {
3550 mvwprintw(subWin, 1, 1, "Time = %d", i);
3551 wrefresh(subWin);
3552 napms(1000);
3553 flushinp();
3556 delwin(subWin);
3557 werase(win);
3558 flash();
3559 wrefresh(win);
3560 napms(1000);
3562 mvwaddstr(win, 2, 1,
3563 "If you were still typing when the window timer expired,");
3564 mvwaddstr(win, 3, 1,
3565 "or else you typed nothing at all while it was running,");
3566 mvwaddstr(win, 4, 1,
3567 "test was invalid. You'll see garbage or nothing at all. ");
3568 mvwaddstr(win, 6, 1, "Press a key");
3569 wmove(win, 9, 10);
3570 wrefresh(win);
3571 echo();
3572 wGetchar(win);
3573 flushinp();
3574 mvwaddstr(win, 12, 0,
3575 "If you see any key other than what you typed, flushinp() is broken.");
3576 Continue(win);
3578 wmove(win, 9, 10);
3579 wdelch(win);
3580 wrefresh(win);
3581 wmove(win, 12, 0);
3582 clrtoeol();
3583 waddstr(win,
3584 "What you typed should now have been deleted; if not, wdelch() failed.");
3585 Continue(win);
3587 cbreak();
3590 /****************************************************************************
3592 * Menu test
3594 ****************************************************************************/
3596 #if USE_LIBMENU
3598 #define MENU_Y 8
3599 #define MENU_X 8
3601 static int
3602 menu_virtualize(int c)
3604 if (c == '\n' || c == KEY_EXIT)
3605 return (MAX_COMMAND + 1);
3606 else if (c == 'u')
3607 return (REQ_SCR_ULINE);
3608 else if (c == 'd')
3609 return (REQ_SCR_DLINE);
3610 else if (c == 'b' || c == KEY_NPAGE)
3611 return (REQ_SCR_UPAGE);
3612 else if (c == 'f' || c == KEY_PPAGE)
3613 return (REQ_SCR_DPAGE);
3614 else if (c == 'n' || c == KEY_DOWN)
3615 return (REQ_NEXT_ITEM);
3616 else if (c == 'p' || c == KEY_UP)
3617 return (REQ_PREV_ITEM);
3618 else if (c == ' ')
3619 return (REQ_TOGGLE_ITEM);
3620 else {
3621 if (c != KEY_MOUSE)
3622 beep();
3623 return (c);
3627 static const char *animals[] =
3629 "Lions", "Tigers", "Bears", "(Oh my!)", "Newts", "Platypi", "Lemurs",
3630 (char *) 0
3633 static void
3634 menu_test(void)
3636 MENU *m;
3637 ITEM *items[SIZEOF(animals)];
3638 ITEM **ip = items;
3639 const char **ap;
3640 int mrows, mcols, c;
3641 WINDOW *menuwin;
3643 #ifdef NCURSES_MOUSE_VERSION
3644 mousemask(ALL_MOUSE_EVENTS, (mmask_t *) 0);
3645 #endif
3646 mvaddstr(0, 0, "This is the menu test:");
3647 mvaddstr(2, 0, " Use up and down arrow to move the select bar.");
3648 mvaddstr(3, 0, " 'n' and 'p' act like arrows.");
3649 mvaddstr(4, 0,
3650 " 'b' and 'f' scroll up/down (page), 'u' and 'd' (line).");
3651 mvaddstr(5, 0, " Press return to exit.");
3652 refresh();
3654 for (ap = animals; *ap; ap++)
3655 *ip++ = new_item(*ap, "");
3656 *ip = (ITEM *) 0;
3658 m = new_menu(items);
3660 set_menu_format(m, (SIZEOF(animals) + 1) / 2, 1);
3661 scale_menu(m, &mrows, &mcols);
3663 menuwin = newwin(mrows + 2, mcols + 2, MENU_Y, MENU_X);
3664 set_menu_win(m, menuwin);
3665 keypad(menuwin, TRUE);
3666 box(menuwin, 0, 0);
3668 set_menu_sub(m, derwin(menuwin, mrows, mcols, 1, 1));
3670 post_menu(m);
3672 while ((c = menu_driver(m, menu_virtualize(wGetchar(menuwin)))) != E_UNKNOWN_COMMAND) {
3673 if (c == E_REQUEST_DENIED)
3674 beep();
3675 continue;
3678 (void) mvprintw(LINES - 2, 0,
3679 "You chose: %s\n", item_name(current_item(m)));
3680 (void) addstr("Press any key to continue...");
3681 wGetchar(stdscr);
3683 unpost_menu(m);
3684 delwin(menuwin);
3686 free_menu(m);
3687 for (ip = items; *ip; ip++)
3688 free_item(*ip);
3689 #ifdef NCURSES_MOUSE_VERSION
3690 mousemask(0, (mmask_t *) 0);
3691 #endif
3694 #ifdef TRACE
3695 #define T_TBL(name) { #name, name }
3696 static struct {
3697 const char *name;
3698 int mask;
3699 } t_tbl[] = {
3701 T_TBL(TRACE_DISABLE),
3702 T_TBL(TRACE_TIMES),
3703 T_TBL(TRACE_TPUTS),
3704 T_TBL(TRACE_UPDATE),
3705 T_TBL(TRACE_MOVE),
3706 T_TBL(TRACE_CHARPUT),
3707 T_TBL(TRACE_ORDINARY),
3708 T_TBL(TRACE_CALLS),
3709 T_TBL(TRACE_VIRTPUT),
3710 T_TBL(TRACE_IEVENT),
3711 T_TBL(TRACE_BITS),
3712 T_TBL(TRACE_ICALLS),
3713 T_TBL(TRACE_CCALLS),
3714 T_TBL(TRACE_DATABASE),
3715 T_TBL(TRACE_ATTRS),
3716 T_TBL(TRACE_MAXIMUM),
3718 (char *) 0, 0
3722 static char *
3723 tracetrace(int tlevel)
3725 static char *buf;
3726 int n;
3728 if (buf == 0) {
3729 size_t need = 12;
3730 for (n = 0; t_tbl[n].name != 0; n++)
3731 need += strlen(t_tbl[n].name) + 2;
3732 buf = (char *) malloc(need);
3734 sprintf(buf, "0x%02x = {", tlevel);
3735 if (tlevel == 0) {
3736 sprintf(buf + strlen(buf), "%s, ", t_tbl[0].name);
3737 } else {
3738 for (n = 1; t_tbl[n].name != 0; n++)
3739 if ((tlevel & t_tbl[n].mask) == t_tbl[n].mask) {
3740 strcat(buf, t_tbl[n].name);
3741 strcat(buf, ", ");
3744 if (buf[strlen(buf) - 2] == ',')
3745 buf[strlen(buf) - 2] = '\0';
3746 return (strcat(buf, "}"));
3749 /* fake a dynamically reconfigurable menu using the 0th entry to deselect
3750 * the others
3752 static int
3753 run_trace_menu(MENU * m)
3755 ITEM **items;
3756 ITEM *i, **p;
3758 for (;;) {
3759 bool changed = FALSE;
3760 switch (menu_driver(m, menu_virtualize(wGetchar(menu_win(m))))) {
3761 case E_UNKNOWN_COMMAND:
3762 return FALSE;
3763 default:
3764 items = menu_items(m);
3765 i = current_item(m);
3766 if (i == items[0]) {
3767 if (item_value(i)) {
3768 for (p = items + 1; *p != 0; p++)
3769 if (item_value(*p)) {
3770 set_item_value(*p, FALSE);
3771 changed = TRUE;
3774 } else {
3775 for (p = items + 1; *p != 0; p++)
3776 if (item_value(*p)) {
3777 set_item_value(items[0], FALSE);
3778 changed = TRUE;
3779 break;
3782 if (!changed)
3783 return TRUE;
3788 static void
3789 trace_set(void)
3790 /* interactively set the trace level */
3792 MENU *m;
3793 ITEM *items[SIZEOF(t_tbl)];
3794 ITEM **ip = items;
3795 int mrows, mcols, newtrace;
3796 int n;
3797 WINDOW *menuwin;
3799 mvaddstr(0, 0, "Interactively set trace level:");
3800 mvaddstr(2, 0, " Press space bar to toggle a selection.");
3801 mvaddstr(3, 0, " Use up and down arrow to move the select bar.");
3802 mvaddstr(4, 0, " Press return to set the trace level.");
3803 mvprintw(6, 0, "(Current trace level is %s)", tracetrace(_nc_tracing));
3805 refresh();
3807 for (n = 0; t_tbl[n].name != 0; n++)
3808 *ip++ = new_item(t_tbl[n].name, "");
3809 *ip = (ITEM *) 0;
3811 m = new_menu(items);
3813 set_menu_format(m, 0, 2);
3814 scale_menu(m, &mrows, &mcols);
3816 menu_opts_off(m, O_ONEVALUE);
3817 menuwin = newwin(mrows + 2, mcols + 2, MENU_Y, MENU_X);
3818 set_menu_win(m, menuwin);
3819 keypad(menuwin, TRUE);
3820 box(menuwin, 0, 0);
3822 set_menu_sub(m, derwin(menuwin, mrows, mcols, 1, 1));
3824 post_menu(m);
3826 for (ip = menu_items(m); *ip; ip++) {
3827 int mask = t_tbl[item_index(*ip)].mask;
3828 if (mask == 0)
3829 set_item_value(*ip, _nc_tracing == 0);
3830 else if ((mask & _nc_tracing) == mask)
3831 set_item_value(*ip, TRUE);
3834 while (run_trace_menu(m))
3835 continue;
3837 newtrace = 0;
3838 for (ip = menu_items(m); *ip; ip++)
3839 if (item_value(*ip))
3840 newtrace |= t_tbl[item_index(*ip)].mask;
3841 trace(newtrace);
3842 _tracef("trace level interactively set to %s", tracetrace(_nc_tracing));
3844 (void) mvprintw(LINES - 2, 0,
3845 "Trace level is %s\n", tracetrace(_nc_tracing));
3846 (void) addstr("Press any key to continue...");
3847 wGetchar(stdscr);
3849 unpost_menu(m);
3850 delwin(menuwin);
3852 free_menu(m);
3853 for (ip = items; *ip; ip++)
3854 free_item(*ip);
3856 #endif /* TRACE */
3857 #endif /* USE_LIBMENU */
3859 /****************************************************************************
3861 * Forms test
3863 ****************************************************************************/
3864 #if USE_LIBFORM
3865 static FIELD *
3866 make_label(int frow, int fcol, NCURSES_CONST char *label)
3868 FIELD *f = new_field(1, strlen(label), frow, fcol, 0, 0);
3870 if (f) {
3871 set_field_buffer(f, 0, label);
3872 set_field_opts(f, field_opts(f) & ~O_ACTIVE);
3874 return (f);
3877 static FIELD *
3878 make_field(int frow, int fcol, int rows, int cols, bool secure)
3880 FIELD *f = new_field(rows, cols, frow, fcol, 0, secure ? 1 : 0);
3882 if (f) {
3883 set_field_back(f, A_UNDERLINE);
3884 set_field_userptr(f, (void *) 0);
3886 return (f);
3889 static void
3890 display_form(FORM * f)
3892 WINDOW *w;
3893 int rows, cols;
3895 scale_form(f, &rows, &cols);
3897 if ((w = newwin(rows + 2, cols + 4, 0, 0)) != (WINDOW *) 0) {
3898 set_form_win(f, w);
3899 set_form_sub(f, derwin(w, rows, cols, 1, 2));
3900 box(w, 0, 0);
3901 keypad(w, TRUE);
3904 if (post_form(f) != E_OK)
3905 wrefresh(w);
3908 static void
3909 erase_form(FORM * f)
3911 WINDOW *w = form_win(f);
3912 WINDOW *s = form_sub(f);
3914 unpost_form(f);
3915 werase(w);
3916 wrefresh(w);
3917 delwin(s);
3918 delwin(w);
3921 static int
3922 edit_secure(FIELD * me, int c)
3924 int rows, cols, frow, fcol, nrow, nbuf;
3926 if (field_info(me, &rows, &cols, &frow, &fcol, &nrow, &nbuf) == E_OK
3927 && nbuf > 0) {
3928 char temp[80];
3929 long len;
3931 strcpy(temp, field_buffer(me, 1));
3932 len = (long) (char *) field_userptr(me);
3933 if (c <= KEY_MAX) {
3934 if (isgraph(c)) {
3935 temp[len++] = c;
3936 temp[len] = 0;
3937 set_field_buffer(me, 1, temp);
3938 c = '*';
3939 } else {
3940 c = 0;
3942 } else {
3943 switch (c) {
3944 case REQ_BEG_FIELD:
3945 case REQ_CLR_EOF:
3946 case REQ_CLR_EOL:
3947 case REQ_DEL_LINE:
3948 case REQ_DEL_WORD:
3949 case REQ_DOWN_CHAR:
3950 case REQ_END_FIELD:
3951 case REQ_INS_CHAR:
3952 case REQ_INS_LINE:
3953 case REQ_LEFT_CHAR:
3954 case REQ_NEW_LINE:
3955 case REQ_NEXT_WORD:
3956 case REQ_PREV_WORD:
3957 case REQ_RIGHT_CHAR:
3958 case REQ_UP_CHAR:
3959 c = 0; /* we don't want to do inline editing */
3960 break;
3961 case REQ_CLR_FIELD:
3962 if (len) {
3963 temp[0] = 0;
3964 set_field_buffer(me, 1, temp);
3966 break;
3967 case REQ_DEL_CHAR:
3968 case REQ_DEL_PREV:
3969 if (len) {
3970 temp[--len] = 0;
3971 set_field_buffer(me, 1, temp);
3973 break;
3976 set_field_userptr(me, (void *) len);
3978 return c;
3981 static int
3982 form_virtualize(FORM * f, WINDOW *w)
3984 static const struct {
3985 int code;
3986 int result;
3987 } lookup[] = {
3989 CTRL('A'), REQ_NEXT_CHOICE
3992 CTRL('B'), REQ_PREV_WORD
3995 CTRL('C'), REQ_CLR_EOL
3998 CTRL('D'), REQ_DOWN_FIELD
4001 CTRL('E'), REQ_END_FIELD
4004 CTRL('F'), REQ_NEXT_PAGE
4007 CTRL('G'), REQ_DEL_WORD
4010 CTRL('H'), REQ_DEL_PREV
4013 CTRL('I'), REQ_INS_CHAR
4016 CTRL('K'), REQ_CLR_EOF
4019 CTRL('L'), REQ_LEFT_FIELD
4022 CTRL('M'), REQ_NEW_LINE
4025 CTRL('N'), REQ_NEXT_FIELD
4028 CTRL('O'), REQ_INS_LINE
4031 CTRL('P'), REQ_PREV_FIELD
4034 CTRL('R'), REQ_RIGHT_FIELD
4037 CTRL('S'), REQ_BEG_FIELD
4040 CTRL('U'), REQ_UP_FIELD
4043 CTRL('V'), REQ_DEL_CHAR
4046 CTRL('W'), REQ_NEXT_WORD
4049 CTRL('X'), REQ_CLR_FIELD
4052 CTRL('Y'), REQ_DEL_LINE
4055 CTRL('Z'), REQ_PREV_CHOICE
4058 ESCAPE, MAX_FORM_COMMAND + 1
4061 KEY_BACKSPACE, REQ_DEL_PREV
4064 KEY_DOWN, REQ_DOWN_CHAR
4067 KEY_END, REQ_LAST_FIELD
4070 KEY_HOME, REQ_FIRST_FIELD
4073 KEY_LEFT, REQ_LEFT_CHAR
4076 KEY_LL, REQ_LAST_FIELD
4079 KEY_NEXT, REQ_NEXT_FIELD
4082 KEY_NPAGE, REQ_NEXT_PAGE
4085 KEY_PPAGE, REQ_PREV_PAGE
4088 KEY_PREVIOUS, REQ_PREV_FIELD
4091 KEY_RIGHT, REQ_RIGHT_CHAR
4094 KEY_UP, REQ_UP_CHAR
4097 QUIT, MAX_FORM_COMMAND + 1
4101 static int mode = REQ_INS_MODE;
4102 int c = wGetchar(w);
4103 unsigned n;
4104 FIELD *me = current_field(f);
4106 if (c == CTRL(']')) {
4107 if (mode == REQ_INS_MODE)
4108 mode = REQ_OVL_MODE;
4109 else
4110 mode = REQ_INS_MODE;
4111 c = mode;
4112 } else {
4113 for (n = 0; n < SIZEOF(lookup); n++) {
4114 if (lookup[n].code == c) {
4115 c = lookup[n].result;
4116 break;
4122 * Force the field that the user is typing into to be in reverse video,
4123 * while the other fields are shown underlined.
4125 if (c <= KEY_MAX) {
4126 c = edit_secure(me, c);
4127 set_field_back(me, A_REVERSE);
4128 } else if (c <= MAX_FORM_COMMAND) {
4129 c = edit_secure(me, c);
4130 set_field_back(me, A_UNDERLINE);
4132 return c;
4135 static int
4136 my_form_driver(FORM * form, int c)
4138 if (c == (MAX_FORM_COMMAND + 1)
4139 && form_driver(form, REQ_VALIDATION) == E_OK)
4140 return (TRUE);
4141 else {
4142 beep();
4143 return (FALSE);
4148 * Allow a middle initial, optionally with a '.' to end it.
4150 static bool
4151 mi_field_check(FIELD * fld, const void *data GCC_UNUSED)
4153 char *s = field_buffer(fld, 0);
4154 int state = 0;
4155 int n;
4157 for (n = 0; s[n] != '\0'; ++n) {
4158 switch (state) {
4159 case 0:
4160 if (s[n] == '.') {
4161 if (n != 1)
4162 return FALSE;
4163 state = 2;
4164 } else if (isspace(UChar(s[n]))) {
4165 state = 2;
4167 break;
4168 case 2:
4169 if (!isspace(UChar(s[n])))
4170 return FALSE;
4171 break;
4175 /* force the form to display a leading capital */
4176 if (islower(UChar(s[0]))) {
4177 s[0] = toupper(UChar(s[0]));
4178 set_field_buffer(fld, 0, s);
4180 return TRUE;
4183 static bool
4184 mi_char_check(int ch, const void *data GCC_UNUSED)
4186 return ((isalpha(ch) || ch == '.') ? TRUE : FALSE);
4190 * Passwords should be at least 6 characters.
4192 static bool
4193 pw_field_check(FIELD * fld, const void *data GCC_UNUSED)
4195 char *s = field_buffer(fld, 0);
4196 int n;
4198 for (n = 0; s[n] != '\0'; ++n) {
4199 if (isspace(UChar(s[n]))) {
4200 if (n < 6)
4201 return FALSE;
4204 return TRUE;
4207 static bool
4208 pw_char_check(int ch, const void *data GCC_UNUSED)
4210 return (isgraph(ch) ? TRUE : FALSE);
4213 static void
4214 demo_forms(void)
4216 WINDOW *w;
4217 FORM *form;
4218 FIELD *f[12], *secure;
4219 FIELDTYPE *fty_middle = new_fieldtype(mi_field_check, mi_char_check);
4220 FIELDTYPE *fty_passwd = new_fieldtype(pw_field_check, pw_char_check);
4221 int finished = 0, c;
4222 unsigned n = 0;
4224 move(18, 0);
4225 addstr("Defined form-traversal keys: ^Q/ESC- exit form\n");
4226 addstr("^N -- go to next field ^P -- go to previous field\n");
4227 addstr("Home -- go to first field End -- go to last field\n");
4228 addstr("^L -- go to field to left ^R -- go to field to right\n");
4229 addstr("^U -- move upward to field ^D -- move downward to field\n");
4230 addstr("^W -- go to next word ^B -- go to previous word\n");
4231 addstr("^S -- go to start of field ^E -- go to end of field\n");
4232 addstr("^H -- delete previous char ^Y -- delete line\n");
4233 addstr("^G -- delete current word ^C -- clear to end of line\n");
4234 addstr("^K -- clear to end of field ^X -- clear field\n");
4235 addstr("Arrow keys move within a field as you would expect.");
4237 mvaddstr(4, 57, "Forms Entry Test");
4239 refresh();
4241 /* describe the form */
4242 f[n++] = make_label(0, 15, "Sample Form");
4244 f[n++] = make_label(2, 0, "Last Name");
4245 f[n++] = make_field(3, 0, 1, 18, FALSE);
4246 set_field_type(f[n - 1], TYPE_ALPHA, 1);
4248 f[n++] = make_label(2, 20, "First Name");
4249 f[n++] = make_field(3, 20, 1, 12, FALSE);
4250 set_field_type(f[n - 1], TYPE_ALPHA, 1);
4252 f[n++] = make_label(2, 34, "Middle Name");
4253 f[n++] = make_field(3, 34, 1, 12, FALSE);
4254 set_field_type(f[n - 1], fty_middle);
4256 f[n++] = make_label(5, 0, "Comments");
4257 f[n++] = make_field(6, 0, 4, 46, FALSE);
4259 f[n++] = make_label(5, 20, "Password:");
4260 secure =
4261 f[n++] = make_field(5, 30, 1, 9, TRUE);
4262 set_field_type(f[n - 1], fty_passwd);
4263 f[n++] = (FIELD *) 0;
4265 form = new_form(f);
4267 display_form(form);
4269 w = form_win(form);
4270 raw();
4271 nonl(); /* lets us read ^M's */
4272 while (!finished) {
4273 switch (form_driver(form, c = form_virtualize(form, w))) {
4274 case E_OK:
4275 mvaddstr(5, 57, field_buffer(secure, 1));
4276 clrtoeol();
4277 refresh();
4278 break;
4279 case E_UNKNOWN_COMMAND:
4280 finished = my_form_driver(form, c);
4281 break;
4282 default:
4283 beep();
4284 break;
4288 erase_form(form);
4290 free_form(form);
4291 for (c = 0; f[c] != 0; c++)
4292 free_field(f[c]);
4293 noraw();
4294 nl();
4296 #endif /* USE_LIBFORM */
4298 /****************************************************************************
4300 * Overlap test
4302 ****************************************************************************/
4304 static void
4305 fillwin(WINDOW *win, char ch)
4307 int y, x;
4308 int y1, x1;
4310 getmaxyx(win, y1, x1);
4311 for (y = 0; y < y1; y++) {
4312 wmove(win, y, 0);
4313 for (x = 0; x < x1; x++)
4314 waddch(win, ch);
4318 static void
4319 crosswin(WINDOW *win, char ch)
4321 int y, x;
4322 int y1, x1;
4324 getmaxyx(win, y1, x1);
4325 for (y = 0; y < y1; y++) {
4326 for (x = 0; x < x1; x++)
4327 if (((x > (x1 - 1) / 3) && (x <= (2 * (x1 - 1)) / 3))
4328 || (((y > (y1 - 1) / 3) && (y <= (2 * (y1 - 1)) / 3)))) {
4329 wmove(win, y, x);
4330 waddch(win, ch);
4335 static void
4336 overlap_test(void)
4337 /* test effects of overlapping windows */
4339 int ch;
4341 WINDOW *win1 = newwin(9, 20, 3, 3);
4342 WINDOW *win2 = newwin(9, 20, 9, 16);
4344 raw();
4345 refresh();
4346 move(0, 0);
4347 printw("This test shows the behavior of wnoutrefresh() with respect to\n");
4348 printw("the shared region of two overlapping windows A and B. The cross\n");
4349 printw("pattern in each window does not overlap the other.\n");
4351 move(18, 0);
4352 printw("a = refresh A, then B, then doupdate. b = refresh B, then A, then doupdaute\n");
4353 printw("c = fill window A with letter A. d = fill window B with letter B.\n");
4354 printw("e = cross pattern in window A. f = cross pattern in window B.\n");
4355 printw("g = clear window A. h = clear window B.\n");
4356 printw("i = overwrite A onto B. j = overwrite B onto A.\n");
4357 printw("^Q/ESC = terminate test.");
4359 while ((ch = Getchar()) != QUIT && ch != ESCAPE)
4360 switch (ch) {
4361 case 'a': /* refresh window A first, then B */
4362 wnoutrefresh(win1);
4363 wnoutrefresh(win2);
4364 doupdate();
4365 break;
4367 case 'b': /* refresh window B first, then A */
4368 wnoutrefresh(win2);
4369 wnoutrefresh(win1);
4370 doupdate();
4371 break;
4373 case 'c': /* fill window A so it's visible */
4374 fillwin(win1, 'A');
4375 break;
4377 case 'd': /* fill window B so it's visible */
4378 fillwin(win2, 'B');
4379 break;
4381 case 'e': /* cross test pattern in window A */
4382 crosswin(win1, 'A');
4383 break;
4385 case 'f': /* cross test pattern in window A */
4386 crosswin(win2, 'B');
4387 break;
4389 case 'g': /* clear window A */
4390 wclear(win1);
4391 wmove(win1, 0, 0);
4392 break;
4394 case 'h': /* clear window B */
4395 wclear(win2);
4396 wmove(win2, 0, 0);
4397 break;
4399 case 'i': /* overwrite A onto B */
4400 overwrite(win1, win2);
4401 break;
4403 case 'j': /* overwrite B onto A */
4404 overwrite(win2, win1);
4405 break;
4408 delwin(win2);
4409 delwin(win1);
4410 erase();
4411 endwin();
4414 /****************************************************************************
4416 * Main sequence
4418 ****************************************************************************/
4420 static bool
4421 do_single_test(const char c)
4422 /* perform a single specified test */
4424 switch (c) {
4425 case 'a':
4426 getch_test();
4427 break;
4429 #if USE_WIDEC_SUPPORT
4430 case 'A':
4431 get_wch_test();
4432 break;
4433 #endif
4435 case 'b':
4436 attr_test();
4437 break;
4439 case 'c':
4440 if (!has_colors())
4441 Cannot("does not support color.");
4442 else
4443 color_test();
4444 break;
4446 case 'd':
4447 if (!has_colors())
4448 Cannot("does not support color.");
4449 else if (!can_change_color())
4450 Cannot("has hardwired color values.");
4451 else
4452 color_edit();
4453 break;
4455 case 'e':
4456 slk_test();
4457 break;
4459 #if USE_WIDEC_SUPPORT
4460 case 'E':
4461 wide_slk_test();
4462 break;
4463 #endif
4464 case 'f':
4465 acs_display();
4466 break;
4468 #if USE_WIDEC_SUPPORT
4469 case 'F':
4470 wide_acs_display();
4471 break;
4472 #endif
4474 #if USE_LIBPANEL
4475 case 'o':
4476 demo_panels();
4477 break;
4478 #endif
4480 case 'g':
4481 acs_and_scroll();
4482 break;
4484 case 'i':
4485 flushinp_test(stdscr);
4486 break;
4488 case 'k':
4489 test_sgr_attributes();
4490 break;
4492 #if USE_LIBMENU
4493 case 'm':
4494 menu_test();
4495 break;
4496 #endif
4498 #if USE_LIBPANEL
4499 case 'p':
4500 demo_pad();
4501 break;
4502 #endif
4504 #if USE_LIBFORM
4505 case 'r':
4506 demo_forms();
4507 break;
4508 #endif
4510 case 's':
4511 overlap_test();
4512 break;
4514 #if USE_LIBMENU && defined(TRACE)
4515 case 't':
4516 trace_set();
4517 break;
4518 #endif
4520 case '?':
4521 break;
4523 default:
4524 return FALSE;
4527 return TRUE;
4530 static void
4531 usage(void)
4533 static const char *const tbl[] =
4535 "Usage: ncurses [options]"
4537 ,"Options:"
4538 #ifdef NCURSES_VERSION
4539 ," -a f,b set default-colors (assumed white-on-black)"
4540 ," -d use default-colors if terminal supports them"
4541 #endif
4542 ," -e fmt specify format for soft-keys test (e)"
4543 ," -f rip-off footer line (can repeat)"
4544 ," -h rip-off header line (can repeat)"
4545 ," -s msec specify nominal time for panel-demo (default: 1, to hold)"
4546 #ifdef TRACE
4547 ," -t mask specify default trace-level (may toggle with ^T)"
4548 #endif
4550 size_t n;
4551 for (n = 0; n < SIZEOF(tbl); n++)
4552 fprintf(stderr, "%s\n", tbl[n]);
4553 ExitProgram(EXIT_FAILURE);
4556 static void
4557 set_terminal_modes(void)
4559 noraw();
4560 cbreak();
4561 noecho();
4562 scrollok(stdscr, TRUE);
4563 idlok(stdscr, TRUE);
4564 keypad(stdscr, TRUE);
4567 #ifdef SIGUSR1
4568 static RETSIGTYPE
4569 announce_sig(int sig)
4571 (void) fprintf(stderr, "Handled signal %d\r\n", sig);
4573 #endif
4575 static int
4576 rip_footer(WINDOW *win, int cols)
4578 wbkgd(win, A_REVERSE);
4579 werase(win);
4580 wmove(win, 0, 0);
4581 wprintw(win, "footer: %d columns", cols);
4582 wnoutrefresh(win);
4583 return OK;
4586 static int
4587 rip_header(WINDOW *win, int cols)
4589 wbkgd(win, A_REVERSE);
4590 werase(win);
4591 wmove(win, 0, 0);
4592 wprintw(win, "header: %d columns", cols);
4593 wnoutrefresh(win);
4594 return OK;
4597 /*+-------------------------------------------------------------------------
4598 main(argc,argv)
4599 --------------------------------------------------------------------------*/
4602 main(int argc, char *argv[])
4604 int command, c;
4605 int my_e_param = 1;
4606 #ifdef NCURSES_VERSION
4607 int default_fg = COLOR_WHITE;
4608 int default_bg = COLOR_BLACK;
4609 bool assumed_colors = FALSE;
4610 bool default_colors = FALSE;
4611 #endif
4613 setlocale(LC_ALL, "");
4615 while ((c = getopt(argc, argv, "a:de:fhs:t:")) != EOF) {
4616 switch (c) {
4617 #ifdef NCURSES_VERSION
4618 case 'a':
4619 assumed_colors = TRUE;
4620 sscanf(optarg, "%d,%d", &default_fg, &default_bg);
4621 break;
4622 case 'd':
4623 default_colors = TRUE;
4624 break;
4625 #endif
4626 case 'e':
4627 my_e_param = atoi(optarg);
4628 #ifdef NCURSES_VERSION
4629 if (my_e_param > 3) /* allow extended layouts */
4630 usage();
4631 #else
4632 if (my_e_param > 1)
4633 usage();
4634 #endif
4635 break;
4636 case 'f':
4637 ripoffline(-1, rip_footer);
4638 break;
4639 case 'h':
4640 ripoffline(1, rip_header);
4641 break;
4642 #if USE_LIBPANEL
4643 case 's':
4644 nap_msec = atol(optarg);
4645 break;
4646 #endif
4647 #ifdef TRACE
4648 case 't':
4649 save_trace = atoi(optarg);
4650 break;
4651 #endif
4652 default:
4653 usage();
4658 * If there's no menus (unlikely for ncurses!), then we'll have to set
4659 * tracing on initially, just in case the user wants to test something that
4660 * doesn't involve wGetchar.
4662 #ifdef TRACE
4663 /* enable debugging */
4664 #if !USE_LIBMENU
4665 trace(save_trace);
4666 #else
4667 if (!isatty(fileno(stdin)))
4668 trace(save_trace);
4669 #endif /* USE_LIBMENU */
4670 #endif /* TRACE */
4672 /* tell it we're going to play with soft keys */
4673 slk_init(my_e_param);
4675 #ifdef SIGUSR1
4676 /* set up null signal catcher so we can see what interrupts to getch do */
4677 signal(SIGUSR1, announce_sig);
4678 #endif
4680 /* we must initialize the curses data structure only once */
4681 initscr();
4682 bkgdset(BLANK);
4684 /* tests, in general, will want these modes */
4685 if (has_colors()) {
4686 start_color();
4687 #ifdef NCURSES_VERSION_PATCH
4688 max_colors = COLORS > 16 ? 16 : COLORS;
4689 #if HAVE_USE_DEFAULT_COLORS
4690 if (default_colors)
4691 use_default_colors();
4692 #if NCURSES_VERSION_PATCH >= 20000708
4693 else if (assumed_colors)
4694 assume_default_colors(default_fg, default_bg);
4695 #endif
4696 #endif
4697 #else /* normal SVr4 curses */
4698 max_colors = COLORS > 8 ? 8 : COLORS;
4699 #endif
4700 max_pairs = (max_colors * max_colors);
4701 if (max_pairs < COLOR_PAIRS)
4702 max_pairs = COLOR_PAIRS;
4704 set_terminal_modes();
4705 def_prog_mode();
4708 * Return to terminal mode, so we're guaranteed of being able to
4709 * select terminal commands even if the capabilities are wrong.
4711 endwin();
4713 #if HAVE_CURSES_VERSION
4714 (void) printf("Welcome to %s. Press ? for help.\n", curses_version());
4715 #elif defined(NCURSES_VERSION_MAJOR) && defined(NCURSES_VERSION_MINOR) && defined(NCURSES_VERSION_PATCH)
4716 (void) printf("Welcome to ncurses %d.%d.%d. Press ? for help.\n",
4717 NCURSES_VERSION_MAJOR,
4718 NCURSES_VERSION_MINOR,
4719 NCURSES_VERSION_PATCH);
4720 #else
4721 (void) puts("Welcome to ncurses. Press ? for help.");
4722 #endif
4724 do {
4725 (void) puts("This is the ncurses main menu");
4726 (void) puts("a = keyboard and mouse input test");
4727 #if USE_WIDEC_SUPPORT
4728 (void) puts("A = wide-character keyboard and mouse input test");
4729 #endif
4730 (void) puts("b = character attribute test");
4731 (void) puts("c = color test pattern");
4732 (void) puts("d = edit RGB color values");
4733 (void) puts("e = exercise soft keys");
4734 #if USE_WIDEC_SUPPORT
4735 (void) puts("E = exercise soft keys using wide-characters");
4736 #endif
4737 (void) puts("f = display ACS characters");
4738 #if USE_WIDEC_SUPPORT
4739 (void) puts("F = display Wide-ACS characters");
4740 #endif
4741 (void) puts("g = display windows and scrolling");
4742 (void) puts("i = test of flushinp()");
4743 (void) puts("k = display character attributes");
4744 #if USE_LIBMENU
4745 (void) puts("m = menu code test");
4746 #endif
4747 #if USE_LIBPANEL
4748 (void) puts("o = exercise panels library");
4749 (void) puts("p = exercise pad features");
4750 (void) puts("q = quit");
4751 #endif
4752 #if USE_LIBFORM
4753 (void) puts("r = exercise forms code");
4754 #endif
4755 (void) puts("s = overlapping-refresh test");
4756 #if USE_LIBMENU && defined(TRACE)
4757 (void) puts("t = set trace level");
4758 #endif
4759 (void) puts("? = repeat this command summary");
4761 (void) fputs("> ", stdout);
4762 (void) fflush(stdout); /* necessary under SVr4 curses */
4765 * This used to be an 'fgets()' call. However (on Linux, at least)
4766 * mixing stream I/O and 'read()' (used in the library) causes the
4767 * input stream to be flushed when switching between the two.
4769 command = 0;
4770 for (;;) {
4771 char ch;
4772 if (read(fileno(stdin), &ch, 1) <= 0) {
4773 if (command == 0)
4774 command = 'q';
4775 break;
4776 } else if (command == 0 && !isspace(UChar(ch))) {
4777 command = ch;
4778 } else if (ch == '\n' || ch == '\r') {
4779 if (command != 0)
4780 break;
4781 (void) fputs("> ", stdout);
4782 (void) fflush(stdout);
4786 if (do_single_test(command)) {
4788 * This may be overkill; it's intended to reset everything back
4789 * to the initial terminal modes so that tests don't get in
4790 * each other's way.
4792 flushinp();
4793 set_terminal_modes();
4794 reset_prog_mode();
4795 clear();
4796 refresh();
4797 endwin();
4798 if (command == '?') {
4799 (void) puts("This is the ncurses capability tester.");
4800 (void)
4801 puts("You may select a test from the main menu by typing the");
4802 (void)
4803 puts("key letter of the choice (the letter to left of the =)");
4804 (void)
4805 puts("at the > prompt. The commands `x' or `q' will exit.");
4807 continue;
4809 } while
4810 (command != 'q');
4812 ExitProgram(EXIT_SUCCESS);
4815 /* ncurses.c ends here */