1 /****************************************************************************
2 * Copyright (c) 1998 Free Software Foundation, Inc. *
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: *
12 * The above copyright notice and this permission notice shall be included *
13 * in all copies or substantial portions of the Software. *
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. *
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 *
27 ****************************************************************************/
28 /****************************************************************************
31 ncurses.c --- ncurses library exerciser
37 An interactive test module for the ncurses library.
40 Author: Eric S. Raymond <esr@snark.thyrsus.com> 1993
42 $Id: ncurses.c,v 1.108 1998/02/28 01:11:47 tom Exp $
44 ***************************************************************************/
46 #include <test.priv.h>
59 #if HAVE_SYS_TIME_H && HAVE_SYS_TIME_SELECT
63 #include <sys/select.h>
68 #define USE_LIBPANEL 1
71 #define USE_LIBPANEL 0
74 #if HAVE_MENU_H && HAVE_LIBMENU
81 #if HAVE_FORM_H && HAVE_LIBFORM
88 #ifdef NCURSES_VERSION
91 static int save_trace = TRACE_ORDINARY|TRACE_CALLS;
92 extern int _nc_tracing;
101 #define mmask_t chtype /* not specified in XSI */
102 #define attr_t chtype /* not specified in XSI */
103 #define ACS_S3 (acs_map['p']) /* scan line 3 */
104 #define ACS_S7 (acs_map['r']) /* scan line 7 */
105 #define ACS_LEQUAL (acs_map['y']) /* less/equal */
106 #define ACS_GEQUAL (acs_map['z']) /* greater/equal */
107 #define ACS_PI (acs_map['{']) /* Pi */
108 #define ACS_NEQUAL (acs_map['|']) /* not equal */
109 #define ACS_STERLING (acs_map['}']) /* UK pound sign */
113 #define P(string) printw("%s\n", string)
115 #define CTRL(x) ((x) & 0x1f)
118 #define QUIT CTRL('Q')
119 #define ESCAPE CTRL('[')
120 #define BLANK ' ' /* this is the background character */
122 /* The behavior of mvhline, mvvline for negative/zero length is unspecified,
123 * though we can rely on negative x/y values to stop the macro.
125 static void do_h_line(int y, int x, chtype c, int to)
128 mvhline(y, x, c, (to) - (x));
131 static void do_v_line(int y, int x, chtype c, int to)
134 mvvline(y, x, c, (to) - (y));
137 /* Common function to allow ^T to toggle trace-mode in the middle of a test
138 * so that trace-files can be made smaller.
140 static int wGetchar(WINDOW *win)
144 while ((c = wgetch(win)) == CTRL('T')) {
146 save_trace = _nc_tracing;
147 _tracef("TOGGLE-TRACING OFF");
150 _nc_tracing = save_trace;
154 _tracef("TOGGLE-TRACING ON");
161 #define Getchar() wGetchar(stdscr)
163 static void Pause(void)
166 addstr("Press any key to continue... ");
170 static void Cannot(const char *what)
172 printw("\nThis %s terminal %s\n\n", getenv("TERM"), what);
176 static void ShellOut(bool message)
179 addstr("Shelling out...");
184 addstr("returned from shellout.\n");
188 /****************************************************************************
190 * Character input test
192 ****************************************************************************/
194 static void getch_test(void)
195 /* test the keypad feature */
199 int incount = 0, firsttime = 0;
200 bool blocking = TRUE;
205 #ifdef NCURSES_MOUSE_VERSION
206 mousemask(ALL_MOUSE_EVENTS, (mmask_t *)0);
209 (void) printw("Delay in 10ths of a second (<CR> for blocking input)? ");
217 timeout(atoi(buf) * 100);
227 printw("Key pressed: %04o ", c);
228 #ifdef NCURSES_MOUSE_VERSION
234 printw("KEY_MOUSE, %s\n", _tracemouse(&event));
237 #endif /* NCURSES_MOUSE_VERSION */
240 (void) addstr(keyname(c));
247 (void) printw("M-%c", c2);
249 (void) printw("M-%s", unctrl(c2));
250 addstr(" (high-half character)\n");
255 (void) printw("%c (ASCII printable character)\n", c);
257 (void) printw("%s (ASCII control character)\n", unctrl(c));
267 addstr("getstr test: ");
268 echo(); getstr(buf); noecho();
269 printw("I saw `%s'.\n", buf);
275 if (c == 'x' || c == 'q' || (c == ERR && blocking))
279 addstr("Type any key to see its keypad value. Also:\n");
280 addstr("g -- triggers a getstr test\n");
281 addstr("s -- shell out\n");
282 addstr("q -- quit\n");
283 addstr("? -- repeats this help message\n");
286 while ((c = Getchar()) == ERR)
288 (void) printw("%05d: input timed out\n", incount++);
290 (void) printw("%05d: input error\n", incount++);
295 #ifdef NCURSES_MOUSE_VERSION
296 mousemask(0, (mmask_t *)0);
305 static int show_attr(int row, int skip, chtype attr, const char *name, bool once)
307 mvprintw(row, 8, "%s mode:", name);
308 mvprintw(row, 24, "|");
309 if (skip) printw("%*s", skip, " ");
314 addstr("abcde fghij klmno pqrst uvwxy z");
317 if (skip) printw("%*s", skip, " ");
319 if (attr != A_NORMAL && !(termattrs() & attr))
324 static bool attr_getc(int *skip, int *fg, int *bg)
331 } else if (ch == CTRL('L')) {
335 } else if (has_colors()) {
337 case 'f': *fg = (*fg + 1); break;
338 case 'F': *fg = (*fg - 1); break;
339 case 'b': *bg = (*bg + 1); break;
340 case 'B': *bg = (*bg - 1); break;
344 if (*fg >= COLORS) *fg = 0;
345 if (*fg < 0) *fg = COLORS - 1;
346 if (*bg >= COLORS) *bg = 0;
347 if (*bg < 0) *bg = COLORS - 1;
353 static void attr_test(void)
354 /* test text attributes */
357 int skip = tigetnum("xmc");
358 int fg = COLOR_WHITE;
359 int bg = COLOR_BLACK;
360 bool *pairs = (bool *)calloc(COLOR_PAIRS, sizeof(bool));
366 n = skip; /* make it easy */
370 int normal = A_NORMAL | BLANK;
373 int pair = (fg * COLORS) + bg;
375 init_pair(pair, fg, bg);
378 normal |= COLOR_PAIR(pair);
383 mvaddstr(0, 20, "Character attribute test display");
385 row = show_attr(row, n, A_STANDOUT, "STANDOUT", TRUE);
386 row = show_attr(row, n, A_REVERSE, "REVERSE", TRUE);
387 row = show_attr(row, n, A_BOLD, "BOLD", TRUE);
388 row = show_attr(row, n, A_UNDERLINE, "UNDERLINE", TRUE);
389 row = show_attr(row, n, A_DIM, "DIM", TRUE);
390 row = show_attr(row, n, A_BLINK, "BLINK", TRUE);
391 row = show_attr(row, n, A_PROTECT, "PROTECT", TRUE);
392 row = show_attr(row, n, A_INVIS, "INVISIBLE", TRUE);
393 row = show_attr(row, n, A_NORMAL, "NORMAL", FALSE);
396 "This terminal does %shave the magic-cookie glitch",
397 tigetnum("xmc") > -1 ? "" : "not ");
399 "Enter a digit to set gaps on each side of displayed attributes");
403 printw(". f/F/b/F toggle colors (now %d/%d)", fg, bg);
406 } while (attr_getc(&n, &fg, &bg));
408 bkgdset(A_NORMAL | BLANK);
413 /****************************************************************************
415 * Color support tests
417 ****************************************************************************/
419 static NCURSES_CONST char *color_names[] =
431 static void show_color_name(int y, int x, int color)
434 mvprintw(y, x, "%02d ", color);
436 mvaddstr(y, x, color_names[color]);
439 static void color_test(void)
440 /* generate a color test pattern */
443 int base, top, width;
444 NCURSES_CONST char *hello;
447 (void) printw("There are %d color pairs\n", COLOR_PAIRS);
449 width = (COLORS > 8) ? 4 : 8;
450 hello = (COLORS > 8) ? "Test" : "Hello";
452 for (base = 0; base < 2; base++)
454 top = (COLORS > 8) ? 0 : base * (COLORS+3);
456 (void) mvprintw(top + 1, 0,
457 "%dx%d matrix of foreground/background colors, bright *%s*\n",
459 base ? "on" : "off");
460 for (i = 0; i < COLORS; i++)
461 show_color_name(top + 2, (i+1) * width, i);
462 for (i = 0; i < COLORS; i++)
463 show_color_name(top + 3 + i, 0, i);
464 for (i = 1; i < COLOR_PAIRS; i++)
466 init_pair(i, i % COLORS, i / COLORS);
467 attron((attr_t)COLOR_PAIR(i));
469 attron((attr_t)A_BOLD);
470 mvaddstr(top + 3 + (i / COLORS), (i % COLORS + 1) * width, hello);
473 if ((COLORS > 8) || base)
481 static void change_color(int current, int field, int value, int usebase)
483 short red, green, blue;
486 color_content(current, &red, &green, &blue);
488 red = green = blue = 0;
502 if (init_color(current, red, green, blue) == ERR)
506 static void color_edit(void)
507 /* display the color test pattern, without trying to edit colors */
509 int i, this_c = 0, value = 0, current = 0, field = 0;
514 for (i = 0; i < COLORS; i++)
515 init_pair(i, COLOR_WHITE, i);
517 mvprintw(LINES-2, 0, "Number: %d", value);
520 short red, green, blue;
523 mvaddstr(0, 20, "Color RGB Value Editing");
526 for (i = 0; i < COLORS; i++)
528 mvprintw(2 + i, 0, "%c %-8s:",
529 (i == current ? '>' : ' '),
530 (i < (int) SIZEOF(color_names)
531 ? color_names[i] : ""));
532 attrset(COLOR_PAIR(i));
537 * Note: this refresh should *not* be necessary! It works around
538 * a bug in attribute handling that apparently causes the A_NORMAL
539 * attribute sets to interfere with the actual emission of the
540 * color setting somehow. This needs to be fixed.
544 color_content(i, &red, &green, &blue);
546 if (current == i && field == 0) attron(A_STANDOUT);
548 if (current == i && field == 0) attrset(A_NORMAL);
550 if (current == i && field == 1) attron(A_STANDOUT);
551 printw("%04d", green);
552 if (current == i && field == 1) attrset(A_NORMAL);
554 if (current == i && field == 2) attron(A_STANDOUT);
555 printw("%04d", blue);
556 if (current == i && field == 2) attrset(A_NORMAL);
561 mvaddstr(COLORS + 3, 0,
562 "Use up/down to select a color, left/right to change fields.");
563 mvaddstr(COLORS + 4, 0,
564 "Modify field by typing nnn=, nnn-, or nnn+. ? for help.");
566 move(2 + current, 0);
570 if (isdigit(this_c) && !isdigit(last_c))
576 current = (current == 0 ? (COLORS - 1) : current - 1);
580 current = (current == (COLORS - 1) ? 0 : current + 1);
584 field = (field == 2 ? 0 : field + 1);
588 field = (field == 0 ? 2 : field - 1);
591 case '0': case '1': case '2': case '3': case '4':
592 case '5': case '6': case '7': case '8': case '9':
593 value = value * 10 + (this_c - '0');
597 change_color(current, field, value, 1);
601 change_color(current, field, -value, 1);
605 change_color(current, field, value, 0);
610 P(" RGB Value Editing Help");
612 P("You are in the RGB value editor. Use the arrow keys to select one of");
613 P("the fields in one of the RGB triples of the current colors; the one");
614 P("currently selected will be reverse-video highlighted.");
616 P("To change a field, enter the digits of the new value; they are echoed");
617 P("as entered. Finish by typing `='. The change will take effect instantly.");
618 P("To increment or decrement a value, use the same procedure, but finish");
619 P("with a `+' or `-'.");
621 P("To quit, do `x' or 'q'");
635 mvprintw(LINES-2, 0, "Number: %d", value);
638 (this_c != 'x' && this_c != 'q');
644 /****************************************************************************
646 * Soft-key label test
648 ****************************************************************************/
650 static void slk_test(void)
651 /* exercise the soft keys */
664 mvaddstr(0, 20, "Soft Key Exerciser");
668 P("Available commands are:");
670 P("^L -- refresh screen");
671 P("a -- activate or restore soft keys");
672 P("d -- disable soft keys");
673 P("c -- set centered format for labels");
674 P("l -- set left-justified format for labels");
675 P("r -- set right-justified format for labels");
676 P("[12345678] -- set label; labels are numbered 1 through 8");
677 P("e -- erase stdscr (should not erase labels)");
678 P("s -- test scrolling of shortened screen");
679 P("x, q -- return to main menu");
681 P("Note: if activating the soft keys causes your terminal to");
682 P("scroll up one line, your terminal auto-scrolls when anything");
683 P("is written to the last screen position. The ncurses code");
684 P("does not yet handle this gracefully.");
697 mvprintw(20, 0, "Press Q to stop the scrolling-test: ");
698 while ((c = Getchar()) != 'Q' && (c != ERR))
718 case '1': case '2': case '3': case '4':
719 case '5': case '6': case '7': case '8':
720 (void) mvaddstr(20, 0, "Please enter the label value: ");
722 wgetnstr(stdscr, buf, 8);
724 slk_set((c - '0'), buf, fmt);
726 move(20, 0); clrtoeol();
737 ((c = Getchar()) != EOF);
744 /****************************************************************************
746 * Alternate character-set stuff
748 ****************************************************************************/
750 /* ISO 6429: codes 0x80 to 0x9f may be control characters that cause the
751 * terminal to perform functions. The remaining codes can be graphic.
753 static void show_upper_chars(int first)
755 bool C1 = (first == 128);
757 int last = first + 31;
762 mvprintw(0, 20, "Display of %s Character Codes %d to %d",
763 C1 ? "C1" : "GR", first, last);
767 for (code = first; code <= last; code++) {
768 int row = 4 + ((code - first) % 16);
769 int col = ((code - first) / 16) * COLS / 2;
771 sprintf(tmp, "%3d (0x%x)", code, code);
772 mvprintw(row, col, "%*s: ", COLS/4, tmp);
774 nodelay(stdscr, TRUE);
777 /* (yes, this _is_ crude) */
778 while ((reply = Getchar()) != ERR) {
782 nodelay(stdscr, FALSE);
787 static int show_1_acs(int n, const char *name, chtype code)
789 const int height = 16;
790 int row = 4 + (n % height);
791 int col = (n / height) * COLS / 2;
792 mvprintw(row, col, "%*s : ", COLS/4, name);
797 static void show_acs_chars(void)
798 /* display the ACS character set */
802 #define BOTH(name) #name, name
806 mvaddstr(0, 20, "Display of the ACS Character Set");
810 n = show_1_acs(0, BOTH(ACS_ULCORNER));
811 n = show_1_acs(n, BOTH(ACS_LLCORNER));
812 n = show_1_acs(n, BOTH(ACS_URCORNER));
813 n = show_1_acs(n, BOTH(ACS_LRCORNER));
814 n = show_1_acs(n, BOTH(ACS_RTEE));
815 n = show_1_acs(n, BOTH(ACS_LTEE));
816 n = show_1_acs(n, BOTH(ACS_BTEE));
817 n = show_1_acs(n, BOTH(ACS_TTEE));
818 n = show_1_acs(n, BOTH(ACS_HLINE));
819 n = show_1_acs(n, BOTH(ACS_VLINE));
820 n = show_1_acs(n, BOTH(ACS_PLUS));
821 n = show_1_acs(n, BOTH(ACS_S1));
822 n = show_1_acs(n, BOTH(ACS_S9));
823 n = show_1_acs(n, BOTH(ACS_DIAMOND));
824 n = show_1_acs(n, BOTH(ACS_CKBOARD));
825 n = show_1_acs(n, BOTH(ACS_DEGREE));
826 n = show_1_acs(n, BOTH(ACS_PLMINUS));
827 n = show_1_acs(n, BOTH(ACS_BULLET));
828 n = show_1_acs(n, BOTH(ACS_LARROW));
829 n = show_1_acs(n, BOTH(ACS_RARROW));
830 n = show_1_acs(n, BOTH(ACS_DARROW));
831 n = show_1_acs(n, BOTH(ACS_UARROW));
832 n = show_1_acs(n, BOTH(ACS_BOARD));
833 n = show_1_acs(n, BOTH(ACS_LANTERN));
834 n = show_1_acs(n, BOTH(ACS_BLOCK));
835 n = show_1_acs(n, BOTH(ACS_S3));
836 n = show_1_acs(n, BOTH(ACS_S7));
837 n = show_1_acs(n, BOTH(ACS_LEQUAL));
838 n = show_1_acs(n, BOTH(ACS_GEQUAL));
839 n = show_1_acs(n, BOTH(ACS_PI));
840 n = show_1_acs(n, BOTH(ACS_NEQUAL));
841 n = show_1_acs(n, BOTH(ACS_STERLING));
844 static void acs_display(void)
857 show_upper_chars((c - '0') * 32 + 128);
860 mvprintw(LINES-3,0, "Note: ANSI terminals may not display C1 characters.");
861 mvprintw(LINES-2,0, "Select: a=ACS, 0=C1, 1,2,3=GR characters, q=quit");
863 } while ((c = Getchar()) != 'x' && c != 'q');
871 * Graphic-rendition test (adapted from vttest)
874 test_sgr_attributes(void)
878 for (pass = 0; pass < 2; pass++) {
879 int normal = ((pass == 0 ? A_NORMAL : A_REVERSE)) | BLANK;
881 /* Use non-default colors if possible to exercise bce a little */
883 init_pair(1, COLOR_WHITE, COLOR_BLUE);
884 normal |= COLOR_PAIR(1);
888 mvprintw( 1,20, "Graphic rendition test pattern:");
890 mvprintw( 4, 1, "vanilla");
892 #define set_sgr(mask) bkgdset((normal^(mask)));
894 mvprintw( 4,40, "bold");
896 set_sgr(A_UNDERLINE);
897 mvprintw( 6, 6, "underline");
899 set_sgr(A_BOLD|A_UNDERLINE);
900 mvprintw( 6,45, "bold underline");
903 mvprintw( 8, 1, "blink");
905 set_sgr(A_BLINK|A_BOLD);
906 mvprintw( 8,40, "bold blink");
908 set_sgr(A_UNDERLINE|A_BLINK);
909 mvprintw(10, 6, "underline blink");
911 set_sgr(A_BOLD|A_UNDERLINE|A_BLINK);
912 mvprintw(10,45, "bold underline blink");
915 mvprintw(12, 1, "negative");
917 set_sgr(A_BOLD|A_REVERSE);
918 mvprintw(12,40, "bold negative");
920 set_sgr(A_UNDERLINE|A_REVERSE);
921 mvprintw(14, 6, "underline negative");
923 set_sgr(A_BOLD|A_UNDERLINE|A_REVERSE);
924 mvprintw(14,45, "bold underline negative");
926 set_sgr(A_BLINK|A_REVERSE);
927 mvprintw(16, 1, "blink negative");
929 set_sgr(A_BOLD|A_BLINK|A_REVERSE);
930 mvprintw(16,40, "bold blink negative");
932 set_sgr(A_UNDERLINE|A_BLINK|A_REVERSE);
933 mvprintw(18, 6, "underline blink negative");
935 set_sgr(A_BOLD|A_UNDERLINE|A_BLINK|A_REVERSE);
936 mvprintw(18,45, "bold underline blink negative");
939 mvprintw(LINES-2,1, "%s background. ", pass == 0 ? "Dark" : "Light");
944 bkgdset(A_NORMAL | BLANK);
949 /****************************************************************************
951 * Windows and scrolling tester.
953 ****************************************************************************/
955 #define BOTLINES 4 /* number of line stolen from screen bottom */
963 #define FRAME struct frame
972 /* We need to know if these flags are actually set, so don't look in FRAME.
973 * These names are known to work with SVr4 curses as well as ncurses.
975 static bool HaveKeypad(FRAME *curp)
977 WINDOW *win = (curp ? curp->wind : stdscr);
978 return win->_use_keypad;
981 static bool HaveScroll(FRAME *curp)
983 WINDOW *win = (curp ? curp->wind : stdscr);
987 static void newwin_legend(FRAME *curp)
989 static const struct {
993 { "^C = create window", 0 },
994 { "^N = next window", 0 },
995 { "^P = previous window", 0 },
996 { "^F = scroll forward", 0 },
997 { "^B = scroll backward", 0 },
998 { "^K = keypad(%s)", 1 },
999 { "^S = scrollok(%s)", 2 },
1000 { "^W = save window to file", 0 },
1001 { "^R = restore window", 0 },
1002 #ifdef NCURSES_VERSION
1003 { "^X = resize", 0 },
1005 { "^Q%s = exit", 3 }
1009 bool do_keypad = HaveKeypad(curp);
1010 bool do_scroll = HaveScroll(curp);
1014 for (n = 0; n < SIZEOF(legend); n++) {
1015 switch (legend[n].code) {
1017 strcpy(buf, legend[n].msg);
1020 sprintf(buf, legend[n].msg, do_keypad ? "yes" : "no");
1023 sprintf(buf, legend[n].msg, do_scroll ? "yes" : "no");
1026 sprintf(buf, legend[n].msg, do_keypad ? "/ESC" : "");
1029 getyx(stdscr, y, x);
1030 addstr((COLS < (x + 3 + (int)strlen(buf))) ? "\n" : (n ? ", " : ""));
1036 static void transient(FRAME *curp, NCURSES_CONST char *msg)
1038 newwin_legend(curp);
1041 mvaddstr(LINES - 1, 0, msg);
1047 printw("%s characters are echoed, window should %sscroll.",
1048 HaveKeypad(curp) ? "Non-arrow" : "All other",
1049 HaveScroll(curp) ? "" : "not " );
1053 static void newwin_report(FRAME *curp)
1054 /* report on the cursor's current position, then restore it */
1056 WINDOW *win = (curp != 0) ? curp->wind : stdscr;
1060 transient(curp, (char *)0);
1062 move(LINES - 1, COLS - 17);
1063 printw("Y = %2d X = %2d", y, x);
1070 static pair *selectcell(int uli, int ulj, int lri, int lrj)
1071 /* arrows keys move cursor, return location at current on non-arrow key */
1073 static pair res; /* result cell */
1074 int si = lri - uli + 1; /* depth of the select area */
1075 int sj = lrj - ulj + 1; /* width of the select area */
1076 int i = 0, j = 0; /* offsets into the select area */
1082 move(uli + i, ulj + j);
1083 newwin_report((FRAME *)0);
1087 case KEY_UP: i += si - 1; break;
1088 case KEY_DOWN: i++; break;
1089 case KEY_LEFT: j += sj - 1; break;
1090 case KEY_RIGHT: j++; break;
1092 case ESCAPE: return((pair *)0);
1093 #ifdef NCURSES_MOUSE_VERSION
1099 if (event.y > uli && event.x > ulj) {
1109 default: res.y = uli + i; res.x = ulj + j; return(&res);
1116 static void outerbox(pair ul, pair lr, bool onoff)
1117 /* draw or erase a box *outside* the given pair of corners */
1119 mvaddch(ul.y-1, lr.x-1, onoff ? ACS_ULCORNER : ' ');
1120 mvaddch(ul.y-1, lr.x+1, onoff ? ACS_URCORNER : ' ');
1121 mvaddch(lr.y+1, lr.x+1, onoff ? ACS_LRCORNER : ' ');
1122 mvaddch(lr.y+1, ul.x-1, onoff ? ACS_LLCORNER : ' ');
1123 move(ul.y-1, ul.x); hline(onoff ? ACS_HLINE : ' ', lr.x - ul.x + 1);
1124 move(ul.y, ul.x-1); vline(onoff ? ACS_VLINE : ' ', lr.y - ul.y + 1);
1125 move(lr.y+1, ul.x); hline(onoff ? ACS_HLINE : ' ', lr.x - ul.x + 1);
1126 move(ul.y, lr.x+1); vline(onoff ? ACS_VLINE : ' ', lr.y - ul.y + 1);
1129 static WINDOW *getwindow(void)
1130 /* Ask user for a window definition */
1135 move(0, 0); clrtoeol();
1136 addstr("Use arrows to move cursor, anything else to mark corner 1");
1138 if ((tmp = selectcell(2, 1, LINES-BOTLINES-2, COLS-2)) == (pair *)0)
1139 return((WINDOW *)0);
1140 memcpy(&ul, tmp, sizeof(pair));
1141 mvaddch(ul.y-1, ul.x-1, ACS_ULCORNER);
1142 move(0, 0); clrtoeol();
1143 addstr("Use arrows to move cursor, anything else to mark corner 2");
1145 if ((tmp = selectcell(ul.y, ul.x, LINES-BOTLINES-2, COLS-2)) == (pair *)0)
1146 return((WINDOW *)0);
1147 memcpy(&lr, tmp, sizeof(pair));
1149 rwindow = subwin(stdscr, lr.y - ul.y + 1, lr.x - ul.x + 1, ul.y, ul.x);
1151 outerbox(ul, lr, TRUE);
1156 move(0, 0); clrtoeol();
1160 static void newwin_move(FRAME *curp, int dy, int dx)
1162 WINDOW *win = (curp != 0) ? curp->wind : stdscr;
1166 getyx(win, cur_y, cur_x);
1167 getmaxyx(win, max_y, max_x);
1168 if ((cur_x += dx) < 0)
1170 else if (cur_x >= max_x)
1172 if ((cur_y += dy) < 0)
1174 else if (cur_y >= max_y)
1176 wmove(win, cur_y, cur_x);
1179 static FRAME *delete_framed(FRAME *fp, bool showit)
1183 fp->last->next = fp->next;
1184 fp->next->last = fp->last;
1192 np = (fp == fp->next) ? 0 : fp->next;
1197 static void acs_and_scroll(void)
1198 /* Demonstrate windows */
1202 FRAME *current = (FRAME *)0, *neww;
1203 WINDOW *usescr = stdscr;
1205 #define DUMPFILE "screendump"
1207 #ifdef NCURSES_MOUSE_VERSION
1208 mousemask(BUTTON1_CLICKED, (mmask_t *)0);
1213 transient((FRAME *)0, (char *)0);
1217 neww = (FRAME *) calloc(1, sizeof(FRAME));
1218 if ((neww->wind = getwindow()) == (WINDOW *)0)
1221 if (current == 0) /* First element, */
1223 neww->next = neww; /* so point it at itself */
1228 neww->next = current->next;
1229 neww->last = current;
1230 neww->last->next = neww;
1231 neww->next->last = neww;
1234 /* SVr4 curses sets the keypad on all newly-created windows to
1235 * false. Someone reported that PDCurses makes new windows inherit
1236 * this flag. Remove the following 'keypad()' call to test this
1238 keypad(current->wind, TRUE);
1239 current->do_keypad = HaveKeypad(current);
1240 current->do_scroll = HaveScroll(current);
1243 case CTRL('N'): /* go to next window */
1245 current = current->next;
1248 case CTRL('P'): /* go to previous window */
1250 current = current->last;
1253 case CTRL('F'): /* scroll current window forward */
1255 wscrl(current->wind, 1);
1258 case CTRL('B'): /* scroll current window backwards */
1260 wscrl(current->wind, -1);
1263 case CTRL('K'): /* toggle keypad mode for current */
1265 current->do_keypad = !current->do_keypad;
1266 keypad(current->wind, current->do_keypad);
1272 current->do_scroll = !current->do_scroll;
1273 scrollok(current->wind, current->do_scroll);
1277 case CTRL('W'): /* save and delete window */
1278 if (current == current->next)
1280 if ((fp = fopen(DUMPFILE, "w")) == (FILE *)0)
1281 transient(current, "Can't open screen dump file");
1284 (void) putwin(current->wind, fp);
1287 current = delete_framed(current, TRUE);
1291 case CTRL('R'): /* restore window */
1292 if ((fp = fopen(DUMPFILE, "r")) == (FILE *)0)
1293 transient(current, "Can't open screen dump file");
1296 neww = (FRAME *) calloc(1, sizeof(FRAME));
1298 neww->next = current->next;
1299 neww->last = current;
1300 neww->last->next = neww;
1301 neww->next->last = neww;
1303 neww->wind = getwin(fp);
1306 wrefresh(neww->wind);
1310 #ifdef NCURSES_VERSION
1311 case CTRL('X'): /* resize window */
1317 move(0, 0); clrtoeol();
1318 addstr("Use arrows to move cursor, anything else to mark new corner");
1321 getbegyx(current->wind, ul.y, ul.x);
1323 tmp = selectcell(ul.y, ul.x, LINES-BOTLINES-2, COLS-2);
1324 if (tmp == (pair *)0)
1330 getmaxyx(current->wind, lr.y, lr.x);
1333 outerbox(ul, lr, FALSE);
1334 wnoutrefresh(stdscr);
1336 /* strictly cosmetic hack for the test */
1337 getmaxyx(current->wind, my, mx);
1338 if (my > tmp->y - ul.y)
1340 getyx(current->wind, lr.y, lr.x);
1341 wmove(current->wind, tmp->y - ul.y + 1, 0);
1342 wclrtobot(current->wind);
1343 wmove(current->wind, lr.y, lr.x);
1345 if (mx > tmp->x - ul.x)
1346 for (i = 0; i < my; i++)
1348 wmove(current->wind, i, tmp->x - ul.x + 1);
1349 wclrtoeol(current->wind);
1351 wnoutrefresh(current->wind);
1353 memcpy(&lr, tmp, sizeof(pair));
1354 (void) wresize(current->wind, lr.y-ul.y+0, lr.x-ul.x+0);
1356 getbegyx(current->wind, ul.y, ul.x);
1357 getmaxyx(current->wind, lr.y, lr.x);
1360 outerbox(ul, lr, TRUE);
1361 wnoutrefresh(stdscr);
1363 wnoutrefresh(current->wind);
1364 move(0, 0); clrtoeol();
1368 #endif /* NCURSES_VERSION */
1370 case KEY_F(10): /* undocumented --- use this to test area clears */
1371 selectcell(0, 0, LINES - 1, COLS - 1);
1377 newwin_move(current, -1, 0);
1380 newwin_move(current, 1, 0);
1383 newwin_move(current, 0, -1);
1386 newwin_move(current, 0, 1);
1394 getyx(current->wind, y, x);
1398 x = getmaxx(current->wind) - 1;
1400 mvwdelch(current->wind, y, x);
1410 waddch(current->wind, (chtype)c);
1415 newwin_report(current);
1416 usescr = (current ? current->wind : stdscr);
1419 ((c = wGetchar(usescr)) != QUIT
1420 && !((c == ESCAPE) && (usescr->_use_keypad))
1424 while (current != 0)
1425 current = delete_framed(current, FALSE);
1427 scrollok(stdscr, TRUE); /* reset to driver's default */
1428 #ifdef NCURSES_MOUSE_VERSION
1429 mousemask(0, (mmask_t *)0);
1436 /****************************************************************************
1440 ****************************************************************************/
1454 static unsigned long nap_msec = 1;
1456 static NCURSES_CONST char *mod[] =
1466 /*+-------------------------------------------------------------------------
1468 --------------------------------------------------------------------------*/
1470 wait_a_while(unsigned long msec GCC_UNUSED)
1480 else if(msec > 1000L)
1481 sleep((int)msec/1000L);
1485 } /* end of wait_a_while */
1487 /*+-------------------------------------------------------------------------
1489 --------------------------------------------------------------------------*/
1491 saywhat(NCURSES_CONST char *text)
1493 wmove(stdscr,LINES - 1,0);
1495 waddstr(stdscr, text);
1496 } /* end of saywhat */
1498 /*+-------------------------------------------------------------------------
1499 mkpanel(rows,cols,tly,tlx) - alloc a win and panel and associate them
1500 --------------------------------------------------------------------------*/
1502 mkpanel(int rows, int cols, int tly, int tlx)
1504 WINDOW *win = newwin(rows,cols,tly,tlx);
1509 if((pan = new_panel(win)))
1513 } /* end of mkpanel */
1515 /*+-------------------------------------------------------------------------
1517 --------------------------------------------------------------------------*/
1521 WINDOW *win = panel_window(pan);
1524 } /* end of rmpanel */
1526 /*+-------------------------------------------------------------------------
1528 --------------------------------------------------------------------------*/
1534 } /* end of pflush */
1536 /*+-------------------------------------------------------------------------
1538 --------------------------------------------------------------------------*/
1540 fill_panel(PANEL *pan)
1542 WINDOW *win = panel_window(pan);
1543 int num = ((const char *)panel_userptr(pan))[1];
1548 wprintw(win,"-pan%c-", num);
1549 for(y = 2; y < getmaxy(win) - 1; y++)
1551 for(x = 1; x < getmaxx(win) - 1; x++)
1557 } /* end of fill_panel */
1559 static void demo_panels(void)
1566 for(y = 0; y < LINES - 1; y++)
1568 for(x = 0; x < COLS; x++)
1569 wprintw(stdscr,"%d",(y + x) % 10);
1571 for(y = 0; y < 5; y++)
1573 p1 = mkpanel(LINES/2 - 2, COLS/8 + 1, 0, 0);
1574 w1 = panel_window(p1);
1575 set_panel_userptr(p1,"p1");
1577 p2 = mkpanel(LINES/2 + 1, COLS/7, LINES/4, COLS/10);
1578 w2 = panel_window(p2);
1579 set_panel_userptr(p2,"p2");
1581 p3 = mkpanel(LINES/4, COLS/10, LINES/2, COLS/9);
1582 w3 = panel_window(p3);
1583 set_panel_userptr(p3,"p3");
1585 p4 = mkpanel(LINES/2 - 2, COLS/8, LINES/2 - 2, COLS/3);
1586 w4 = panel_window(p4);
1587 set_panel_userptr(p4,"p4");
1589 p5 = mkpanel(LINES/2 - 2, COLS/8, LINES/2, COLS/2 - 2);
1590 w5 = panel_window(p5);
1591 set_panel_userptr(p5,"p5");
1601 saywhat("press any key to continue");
1602 wait_a_while(nap_msec);
1604 saywhat("h3 s1 s2 s4 s5; press any key to continue");
1612 wait_a_while(nap_msec);
1614 saywhat("s1; press any key to continue");
1617 wait_a_while(nap_msec);
1619 saywhat("s2; press any key to continue");
1622 wait_a_while(nap_msec);
1624 saywhat("m2; press any key to continue");
1625 move_panel(p2, LINES/3 + 1, COLS / 8);
1627 wait_a_while(nap_msec);
1632 wait_a_while(nap_msec);
1634 saywhat("m3; press any key to continue");
1635 move_panel(p3, LINES/4 + 1, COLS / 15);
1637 wait_a_while(nap_msec);
1639 saywhat("b3; press any key to continue");
1642 wait_a_while(nap_msec);
1644 saywhat("s4; press any key to continue");
1647 wait_a_while(nap_msec);
1649 saywhat("s5; press any key to continue");
1652 wait_a_while(nap_msec);
1654 saywhat("t3; press any key to continue");
1657 wait_a_while(nap_msec);
1659 saywhat("t1; press any key to continue");
1662 wait_a_while(nap_msec);
1664 saywhat("t2; press any key to continue");
1667 wait_a_while(nap_msec);
1669 saywhat("t3; press any key to continue");
1672 wait_a_while(nap_msec);
1674 saywhat("t4; press any key to continue");
1677 wait_a_while(nap_msec);
1679 for(itmp = 0; itmp < 6; itmp++)
1681 saywhat("m4; press any key to continue");
1682 wmove(w4, LINES/8, 1);
1683 waddstr(w4,mod[itmp]);
1684 move_panel(p4, LINES/6, itmp*(COLS/8));
1685 wmove(w5, LINES/6, 1);
1686 waddstr(w5,mod[itmp]);
1688 wait_a_while(nap_msec);
1689 saywhat("m5; press any key to continue");
1690 wmove(w4, LINES/6, 1);
1691 waddstr(w4,mod[itmp]);
1692 move_panel(p5, LINES/3 - 1,(itmp*10) + 6);
1693 wmove(w5, LINES/8, 1);
1694 waddstr(w5,mod[itmp]);
1696 wait_a_while(nap_msec);
1699 saywhat("m4; press any key to continue");
1700 move_panel(p4, LINES/6, itmp*(COLS/8));
1702 wait_a_while(nap_msec);
1704 saywhat("t5; press any key to continue");
1707 wait_a_while(nap_msec);
1709 saywhat("t2; press any key to continue");
1712 wait_a_while(nap_msec);
1714 saywhat("t1; press any key to continue");
1717 wait_a_while(nap_msec);
1719 saywhat("d2; press any key to continue");
1722 wait_a_while(nap_msec);
1724 saywhat("h3; press any key to continue");
1727 wait_a_while(nap_msec);
1729 saywhat("d1; press any key to continue");
1732 wait_a_while(nap_msec);
1734 saywhat("d4; press any key to continue");
1737 wait_a_while(nap_msec);
1739 saywhat("d5; press any key to continue");
1742 wait_a_while(nap_msec);
1752 /****************************************************************************
1756 ****************************************************************************/
1760 static bool show_panner_legend = TRUE;
1762 static int panner_legend(int line)
1764 static const char *const legend[] = {
1765 "Use arrow keys (or U,D,L,R) to pan, q to quit (?,t,s flags)",
1766 "Use ! to shell-out. Toggle legend:?, timer:t, scroll mark:s.",
1767 "Use +,- (or j,k) to grow/shrink the panner vertically.",
1768 "Use <,> (or h,l) to grow/shrink the panner horizontally."
1770 int n = (SIZEOF(legend) - (LINES - line));
1771 if (line < LINES && (n >= 0)) {
1773 if (show_panner_legend)
1774 printw("%s", legend[n]);
1776 return show_panner_legend;
1781 static void panner_h_cleanup(int from_y, int from_x, int to_x)
1783 if (!panner_legend(from_y))
1784 do_h_line(from_y, from_x, ' ', to_x);
1787 static void panner_v_cleanup(int from_y, int from_x, int to_y)
1789 if (!panner_legend(from_y))
1790 do_v_line(from_y, from_x, ' ', to_y);
1793 static void panner(WINDOW *pad,
1794 int top_x, int top_y, int porty, int portx,
1795 int (*pgetc)(WINDOW *))
1797 #if HAVE_GETTIMEOFDAY
1798 struct timeval before, after;
1801 bool scrollers = TRUE;
1804 int pxmax, pymax, lowend, highend, c;
1806 getmaxyx(pad, pymax, pxmax);
1807 scrollok(stdscr, FALSE); /* we don't want stdscr to scroll! */
1811 #ifdef NCURSES_VERSION
1813 * During shell-out, the user may have resized the window. Adjust
1814 * the port size of the pad to accommodate this. Ncurses automatically
1815 * resizes all of the normal windows to fit on the new screen.
1817 if (top_x > COLS) top_x = COLS;
1818 if (portx > COLS) portx = COLS;
1819 if (top_y > LINES) top_y = LINES;
1820 if (porty > LINES) porty = LINES;
1830 show_panner_legend = !show_panner_legend;
1831 panner_legend(LINES - 4);
1832 panner_legend(LINES - 3);
1833 panner_legend(LINES - 2);
1834 panner_legend(LINES - 1);
1836 #if HAVE_GETTIMEOFDAY
1840 panner_legend(LINES-1);
1844 scrollers = !scrollers;
1847 /* Move the top-left corner of the pad, keeping the bottom-right
1850 case 'h': /* increase-columns: move left edge to left */
1855 panner_v_cleanup(top_y, top_x, porty);
1860 case 'j': /* decrease-lines: move top-edge down */
1865 panner_h_cleanup(top_y - 1, top_x - (top_x > 0), portx);
1870 case 'k': /* increase-lines: move top-edge up */
1876 panner_h_cleanup(top_y, top_x, portx);
1880 case 'l': /* decrease-columns: move left-edge to right */
1885 panner_v_cleanup(top_y - (top_y > 0), top_x - 1, porty);
1890 /* Move the bottom-right corner of the pad, keeping the top-left
1893 case KEY_IC: /* increase-columns: move right-edge to right */
1894 if (portx >= pxmax || portx >= COLS)
1898 panner_v_cleanup(top_y - (top_y > 0), portx - 1, porty);
1903 case KEY_IL: /* increase-lines: move bottom-edge down */
1904 if (porty >= pymax || porty >= LINES)
1908 panner_h_cleanup(porty - 1, top_x - (top_x > 0), portx);
1913 case KEY_DC: /* decrease-columns: move bottom edge up */
1919 panner_v_cleanup(top_y - (top_y > 0), portx, porty);
1923 case KEY_DL: /* decrease-lines */
1929 panner_h_cleanup(porty, top_x - (top_x > 0), portx);
1933 case KEY_LEFT: /* pan leftwards */
1940 case KEY_RIGHT: /* pan rightwards */
1941 if (basex + portx - (pymax > porty) < pxmax)
1947 case KEY_UP: /* pan upwards */
1954 case KEY_DOWN: /* pan downwards */
1955 if (basey + porty - (pxmax > portx) < pymax)
1966 mvaddch(top_y - 1, top_x - 1, ACS_ULCORNER);
1967 do_v_line(top_y, top_x - 1, ACS_VLINE, porty);
1968 do_h_line(top_y - 1, top_x, ACS_HLINE, portx);
1970 if (scrollers && (pxmax > portx - 1)) {
1971 int length = (portx - top_x - 1);
1972 float ratio = ((float) length) / ((float) pxmax);
1974 lowend = (int)(top_x + (basex * ratio));
1975 highend = (int)(top_x + ((basex + length) * ratio));
1977 do_h_line(porty - 1, top_x, ACS_HLINE, lowend);
1978 if (highend < portx) {
1980 do_h_line(porty - 1, lowend, ' ', highend + 1);
1982 do_h_line(porty - 1, highend + 1, ACS_HLINE, portx);
1985 do_h_line(porty - 1, top_x, ACS_HLINE, portx);
1987 if (scrollers && (pymax > porty - 1)) {
1988 int length = (porty - top_y - 1);
1989 float ratio = ((float) length) / ((float) pymax);
1991 lowend = (int)(top_y + (basey * ratio));
1992 highend = (int)(top_y + ((basey + length) * ratio));
1994 do_v_line(top_y, portx - 1, ACS_VLINE, lowend);
1995 if (highend < porty) {
1997 do_v_line(lowend, portx - 1, ' ', highend + 1);
1999 do_v_line(highend + 1, portx - 1, ACS_VLINE, porty);
2002 do_v_line(top_y, portx - 1, ACS_VLINE, porty);
2004 mvaddch(top_y - 1, portx - 1, ACS_URCORNER);
2005 mvaddch(porty - 1, top_x - 1, ACS_LLCORNER);
2006 mvaddch(porty - 1, portx - 1, ACS_LRCORNER);
2008 #if HAVE_GETTIMEOFDAY
2009 gettimeofday(&before, 0);
2011 wnoutrefresh(stdscr);
2016 porty - (pxmax > portx) - 1,
2017 portx - (pymax > porty) - 1);
2020 #if HAVE_GETTIMEOFDAY
2023 gettimeofday(&after, 0);
2024 elapsed = (after.tv_sec + after.tv_usec / 1.0e6)
2025 - (before.tv_sec + before.tv_usec / 1.0e6);
2026 move(LINES-1, COLS-20);
2027 printw("Secs: %2.03f", elapsed);
2033 ((c = pgetc(pad)) != KEY_EXIT);
2035 scrollok(stdscr, TRUE); /* reset to driver's default */
2039 int padgetch(WINDOW *win)
2043 switch(c = wGetchar(win))
2045 case '!': ShellOut(FALSE); return KEY_REFRESH;
2046 case CTRL('r'): endwin(); refresh(); return KEY_REFRESH;
2047 case CTRL('l'): return KEY_REFRESH;
2048 case 'U': return(KEY_UP);
2049 case 'D': return(KEY_DOWN);
2050 case 'R': return(KEY_RIGHT);
2051 case 'L': return(KEY_LEFT);
2052 case '+': return(KEY_IL);
2053 case '-': return(KEY_DL);
2054 case '>': return(KEY_IC);
2055 case '<': return(KEY_DC);
2056 case ERR: /* FALLTHRU */
2057 case 'q': return(KEY_EXIT);
2062 static void demo_pad(void)
2063 /* Demonstrate pads. */
2066 unsigned gridcount = 0;
2067 WINDOW *panpad = newpad(200, 200);
2069 for (i = 0; i < 200; i++)
2071 for (j = 0; j < 200; j++)
2072 if (i % GRIDSIZE == 0 && j % GRIDSIZE == 0)
2074 if (i == 0 || j == 0)
2075 waddch(panpad, '+');
2077 waddch(panpad, (chtype)('A' + (gridcount++ % 26)));
2079 else if (i % GRIDSIZE == 0)
2080 waddch(panpad, '-');
2081 else if (j % GRIDSIZE == 0)
2082 waddch(panpad, '|');
2084 waddch(panpad, ' ');
2086 panner_legend(LINES - 4);
2087 panner_legend(LINES - 3);
2088 panner_legend(LINES - 2);
2089 panner_legend(LINES - 1);
2091 keypad(panpad, TRUE);
2093 /* Make the pad (initially) narrow enough that a trace file won't wrap.
2094 * We'll still be able to widen it during a test, since that's required
2095 * for testing boundaries.
2097 panner(panpad, 2, 2, LINES - 5, COLS-15, padgetch);
2103 #endif /* USE_LIBPANEL */
2105 /****************************************************************************
2107 * Tests from John Burnell's PDCurses tester
2109 ****************************************************************************/
2111 static void Continue (WINDOW *win)
2115 mvwaddstr(win, 10, 1, " Press any key to continue");
2120 static void flushinp_test(WINDOW *win)
2121 /* Input test, adapted from John Burnell's PDCurses tester */
2123 int w, h, bx, by, sw, sh, i;
2128 getmaxyx(win, h, w);
2129 getbegyx(win, by, bx);
2132 if((subWin = subwin(win, sh, sw, by + h - sh - 2, bx + w - sw - 2)) == 0)
2138 init_pair(2,COLOR_CYAN,COLOR_BLUE);
2139 wattrset(subWin, COLOR_PAIR(2) | A_BOLD);
2142 wattrset(subWin, A_BOLD);
2144 wattrset(subWin, A_BOLD);
2146 box(subWin, ACS_VLINE, ACS_HLINE);
2147 mvwaddstr(subWin, 2, 1, "This is a subwindow");
2151 * This used to set 'nocbreak()'. However, Alexander Lukyanov says that
2152 * it only happened to "work" on SVr4 because that implementation does not
2153 * emulate nocbreak+noecho mode, whereas ncurses does. To get the desired
2154 * test behavior, we're using 'cbreak()', which will allow a single
2155 * character to return without needing a newline. - T.Dickey 1997/10/11.
2158 mvwaddstr(win, 0, 1, "This is a test of the flushinp() call.");
2160 mvwaddstr(win, 2, 1, "Type random keys for 5 seconds.");
2161 mvwaddstr(win, 3, 1,
2162 "These should be discarded (not echoed) after the subwindow goes away.");
2165 for (i = 0; i < 5; i++)
2167 mvwprintw (subWin, 1, 1, "Time = %d", i);
2179 mvwaddstr(win, 2, 1,
2180 "If you were still typing when the window timer expired,");
2181 mvwaddstr(win, 3, 1,
2182 "or else you typed nothing at all while it was running,");
2183 mvwaddstr(win, 4, 1,
2184 "test was invalid. You'll see garbage or nothing at all. ");
2185 mvwaddstr(win, 6, 1, "Press a key");
2191 mvwaddstr(win, 12, 0,
2192 "If you see any key other than what you typed, flushinp() is broken.");
2201 "What you typed should now have been deleted; if not, wdelch() failed.");
2207 /****************************************************************************
2211 ****************************************************************************/
2218 static int menu_virtualize(int c)
2220 if (c == '\n' || c == KEY_EXIT)
2221 return(MAX_COMMAND + 1);
2222 else if (c == 'n' || c == KEY_DOWN)
2223 return(REQ_NEXT_ITEM);
2224 else if (c == 'p' || c == KEY_UP)
2225 return(REQ_PREV_ITEM);
2227 return(REQ_TOGGLE_ITEM);
2232 static const char *animals[] =
2234 "Lions", "Tigers", "Bears", "(Oh my!)", "Newts", "Platypi", "Lemurs",
2238 static void menu_test(void)
2241 ITEM *items[SIZEOF(animals)];
2247 mvaddstr(0, 0, "This is the menu test:");
2248 mvaddstr(2, 0, " Use up and down arrow to move the select bar.");
2249 mvaddstr(3, 0, " 'n' and 'p' act like arrows.");
2250 mvaddstr(4, 0, " Press return to exit.");
2253 for (ap = animals; *ap; ap++)
2254 *ip++ = new_item(*ap, "");
2257 m = new_menu(items);
2259 scale_menu(m, &mrows, &mcols);
2261 menuwin = newwin(mrows + 2, mcols + 2, MENU_Y, MENU_X);
2262 set_menu_win(m, menuwin);
2263 keypad(menuwin, TRUE);
2266 set_menu_sub(m, derwin(menuwin, mrows, mcols, 1, 1));
2270 while (menu_driver(m, menu_virtualize(wGetchar(menuwin))) != E_UNKNOWN_COMMAND)
2273 (void) mvprintw(LINES - 2, 0,
2274 "You chose: %s\n", item_name(current_item(m)));
2275 (void) addstr("Press any key to continue...");
2282 for (ip = items; *ip; ip++)
2287 #define T_TBL(name) { #name, name }
2292 T_TBL(TRACE_DISABLE),
2295 T_TBL(TRACE_UPDATE),
2297 T_TBL(TRACE_CHARPUT),
2298 T_TBL(TRACE_ORDINARY),
2300 T_TBL(TRACE_VIRTPUT),
2301 T_TBL(TRACE_IEVENT),
2303 T_TBL(TRACE_ICALLS),
2304 T_TBL(TRACE_CCALLS),
2305 T_TBL(TRACE_MAXIMUM),
2309 static char *tracetrace(int tlevel)
2316 for (n = 0; t_tbl[n].name != 0; n++)
2317 need += strlen(t_tbl[n].name) + 2;
2318 buf = (char *)malloc(need);
2320 sprintf(buf, "0x%02x = {", tlevel);
2322 sprintf(buf + strlen(buf), "%s, ", t_tbl[0].name);
2324 for (n = 1; t_tbl[n].name != 0; n++)
2325 if ((tlevel & t_tbl[n].mask) == t_tbl[n].mask)
2327 strcat(buf, t_tbl[n].name);
2331 if (buf[strlen(buf) - 2] == ',')
2332 buf[strlen(buf) - 2] = '\0';
2333 return(strcat(buf,"}"));
2336 /* fake a dynamically reconfigurable menu using the 0th entry to deselect
2339 static int run_trace_menu(MENU *m)
2345 bool changed = FALSE;
2346 switch (menu_driver(m, menu_virtualize(wGetchar(menu_win(m))))) {
2347 case E_UNKNOWN_COMMAND:
2350 items = menu_items(m);
2351 i = current_item(m);
2352 if (i == items[0]) {
2353 if (item_value(i)) {
2354 for (p = items+1; *p != 0; p++)
2355 if (item_value(*p)) {
2356 set_item_value(*p, FALSE);
2361 for (p = items+1; *p != 0; p++)
2362 if (item_value(*p)) {
2363 set_item_value(items[0], FALSE);
2374 static void trace_set(void)
2375 /* interactively set the trace level */
2378 ITEM *items[SIZEOF(t_tbl)];
2380 int mrows, mcols, newtrace;
2384 mvaddstr(0, 0, "Interactively set trace level:");
2385 mvaddstr(2, 0, " Press space bar to toggle a selection.");
2386 mvaddstr(3, 0, " Use up and down arrow to move the select bar.");
2387 mvaddstr(4, 0, " Press return to set the trace level.");
2388 mvprintw(6, 0, "(Current trace level is %s)", tracetrace(_nc_tracing));
2392 for (n = 0; t_tbl[n].name != 0; n++)
2393 *ip++ = new_item(t_tbl[n].name, "");
2396 m = new_menu(items);
2398 set_menu_format(m, 0, 2);
2399 scale_menu(m, &mrows, &mcols);
2401 menu_opts_off(m, O_ONEVALUE);
2402 menuwin = newwin(mrows + 2, mcols + 2, MENU_Y, MENU_X);
2403 set_menu_win(m, menuwin);
2404 keypad(menuwin, TRUE);
2407 set_menu_sub(m, derwin(menuwin, mrows, mcols, 1, 1));
2411 for (ip = menu_items(m); *ip; ip++) {
2412 int mask = t_tbl[item_index(*ip)].mask;
2414 set_item_value(*ip, _nc_tracing == 0);
2415 else if ((mask & _nc_tracing) == mask)
2416 set_item_value(*ip, TRUE);
2419 while (run_trace_menu(m))
2423 for (ip = menu_items(m); *ip; ip++)
2424 if (item_value(*ip))
2425 newtrace |= t_tbl[item_index(*ip)].mask;
2427 _tracef("trace level interactively set to %s", tracetrace(_nc_tracing));
2429 (void) mvprintw(LINES - 2, 0,
2430 "Trace level is %s\n", tracetrace(_nc_tracing));
2431 (void) addstr("Press any key to continue...");
2438 for (ip = items; *ip; ip++)
2442 #endif /* USE_LIBMENU */
2444 /****************************************************************************
2448 ****************************************************************************/
2450 static FIELD *make_label(int frow, int fcol, NCURSES_CONST char *label)
2452 FIELD *f = new_field(1, strlen(label), frow, fcol, 0, 0);
2456 set_field_buffer(f, 0, label);
2457 set_field_opts(f, field_opts(f) & ~O_ACTIVE);
2462 static FIELD *make_field(int frow, int fcol, int rows, int cols)
2464 FIELD *f = new_field(rows, cols, frow, fcol, 0, 0);
2467 set_field_back(f, A_UNDERLINE);
2471 static void display_form(FORM *f)
2476 scale_form(f, &rows, &cols);
2478 if ((w =newwin(rows+2, cols+4, 0, 0)) != (WINDOW *)0)
2481 set_form_sub(f, derwin(w, rows, cols, 1, 2));
2486 if (post_form(f) != E_OK)
2490 static void erase_form(FORM *f)
2492 WINDOW *w = form_win(f);
2493 WINDOW *s = form_sub(f);
2502 static int form_virtualize(WINDOW *w)
2504 static int mode = REQ_INS_MODE;
2505 int c = wGetchar(w);
2511 return(MAX_FORM_COMMAND + 1);
2513 /* demo doesn't use these three, leave them in anyway as sample code */
2516 return(REQ_NEXT_PAGE);
2518 return(REQ_PREV_PAGE);
2522 return(REQ_NEXT_FIELD);
2525 return(REQ_PREV_FIELD);
2528 return(REQ_FIRST_FIELD);
2531 return(REQ_LAST_FIELD);
2534 return(REQ_LEFT_FIELD);
2536 return(REQ_RIGHT_FIELD);
2538 return(REQ_UP_FIELD);
2540 return(REQ_DOWN_FIELD);
2543 return(REQ_NEXT_WORD);
2545 return(REQ_PREV_WORD);
2547 return(REQ_BEG_FIELD);
2549 return(REQ_END_FIELD);
2552 return(REQ_LEFT_CHAR);
2554 return(REQ_RIGHT_CHAR);
2556 return(REQ_UP_CHAR);
2558 return(REQ_DOWN_CHAR);
2561 return(REQ_NEW_LINE);
2563 return(REQ_INS_CHAR);
2565 return(REQ_INS_LINE);
2567 return(REQ_DEL_CHAR);
2571 return(REQ_DEL_PREV);
2573 return(REQ_DEL_LINE);
2575 return(REQ_DEL_WORD);
2578 return(REQ_CLR_EOL);
2580 return(REQ_CLR_EOF);
2582 return(REQ_CLR_FIELD);
2584 return(REQ_NEXT_CHOICE);
2586 return(REQ_PREV_CHOICE);
2589 if (mode == REQ_INS_MODE)
2590 return(mode = REQ_OVL_MODE);
2592 return(mode = REQ_INS_MODE);
2599 static int my_form_driver(FORM *form, int c)
2601 if (c == (MAX_FORM_COMMAND + 1)
2602 && form_driver(form, REQ_VALIDATION) == E_OK)
2611 static void demo_forms(void)
2616 int finished = 0, c;
2618 mvaddstr(10, 57, "Forms Entry Test");
2621 addstr("Defined form-traversal keys: ^Q/ESC- exit form\n");
2622 addstr("^N -- go to next field ^P -- go to previous field\n");
2623 addstr("Home -- go to first field End -- go to last field\n");
2624 addstr("^L -- go to field to left ^R -- go to field to right\n");
2625 addstr("^U -- move upward to field ^D -- move downward to field\n");
2626 addstr("^W -- go to next word ^B -- go to previous word\n");
2627 addstr("^S -- go to start of field ^E -- go to end of field\n");
2628 addstr("^H -- delete previous char ^Y -- delete line\n");
2629 addstr("^G -- delete current word ^C -- clear to end of line\n");
2630 addstr("^K -- clear to end of field ^X -- clear field\n");
2631 addstr("Arrow keys move within a field as you would expect.");
2634 /* describe the form */
2635 f[0] = make_label(0, 15, "Sample Form");
2636 f[1] = make_label(2, 0, "Last Name");
2637 f[2] = make_field(3, 0, 1, 18);
2638 f[3] = make_label(2, 20, "First Name");
2639 f[4] = make_field(3, 20, 1, 12);
2640 f[5] = make_label(2, 34, "Middle Name");
2641 f[6] = make_field(3, 34, 1, 12);
2642 f[7] = make_label(5, 0, "Comments");
2643 f[8] = make_field(6, 0, 4, 46);
2654 switch(form_driver(form, c = form_virtualize(w)))
2658 case E_UNKNOWN_COMMAND:
2659 finished = my_form_driver(form, c);
2670 for (c = 0; f[c] != 0; c++)
2674 #endif /* USE_LIBFORM */
2676 /****************************************************************************
2680 ****************************************************************************/
2682 static void fillwin(WINDOW *win, char ch)
2687 getmaxyx(win, y1, x1);
2688 for (y = 0; y < y1; y++)
2691 for (x = 0; x < x1; x++)
2696 static void crosswin(WINDOW *win, char ch)
2701 getmaxyx(win, y1, x1);
2702 for (y = 0; y < y1; y++)
2704 for (x = 0; x < x1; x++)
2705 if (((x > (x1 - 1) / 3) && (x <= (2 * (x1 - 1)) / 3))
2706 || (((y > (y1 - 1) / 3) && (y <= (2 * (y1 - 1)) / 3))))
2714 static void overlap_test(void)
2715 /* test effects of overlapping windows */
2719 WINDOW *win1 = newwin(9, 20, 3, 3);
2720 WINDOW *win2 = newwin(9, 20, 9, 16);
2725 printw("This test shows the behavior of wnoutrefresh() with respect to\n");
2726 printw("the shared region of two overlapping windows A and B. The cross\n");
2727 printw("pattern in each window does not overlap the other.\n");
2731 printw("a = refresh A, then B, then doupdate. b = refresh B, then A, then doupdaute\n");
2732 printw("c = fill window A with letter A. d = fill window B with letter B.\n");
2733 printw("e = cross pattern in window A. f = cross pattern in window B.\n");
2734 printw("g = clear window A. h = clear window B.\n");
2735 printw("i = overwrite A onto B. j = overwrite B onto A.\n");
2736 printw("^Q/ESC = terminate test.");
2738 while ((ch = Getchar()) != QUIT && ch != ESCAPE)
2741 case 'a': /* refresh window A first, then B */
2747 case 'b': /* refresh window B first, then A */
2753 case 'c': /* fill window A so it's visible */
2757 case 'd': /* fill window B so it's visible */
2761 case 'e': /* cross test pattern in window A */
2762 crosswin(win1, 'A');
2765 case 'f': /* cross test pattern in window A */
2766 crosswin(win2, 'B');
2769 case 'g': /* clear window A */
2774 case 'h': /* clear window B */
2779 case 'i': /* overwrite A onto B */
2780 overwrite(win1, win2);
2783 case 'j': /* overwrite B onto A */
2784 overwrite(win2, win1);
2794 /****************************************************************************
2798 ****************************************************************************/
2801 do_single_test(const char c)
2802 /* perform a single specified test */
2816 Cannot("does not support color.");
2823 Cannot("does not support color.");
2824 else if (!can_change_color())
2825 Cannot("has hardwired color values.");
2849 flushinp_test(stdscr);
2853 test_sgr_attributes();
2878 #if USE_LIBMENU && defined(TRACE)
2897 static const char *const tbl[] = {
2898 "Usage: ncurses [options]"
2901 ," -e fmt specify format for soft-keys test (e)"
2902 ," -f rip-off footer line (can repeat)"
2903 ," -h rip-off header line (can repeat)"
2904 ," -s msec specify nominal time for panel-demo (default: 1, to hold)"
2906 ," -t mask specify default trace-level (may toggle with ^T)"
2910 for (n = 0; n < sizeof(tbl)/sizeof(tbl[0]); n++)
2911 fprintf(stderr, "%s\n", tbl[n]);
2916 set_terminal_modes(void)
2921 scrollok(stdscr, TRUE);
2922 idlok(stdscr, TRUE);
2923 keypad(stdscr, TRUE);
2927 static RETSIGTYPE announce_sig(int sig)
2929 (void) fprintf(stderr, "Handled signal %d\r\n", sig);
2933 static int rip_footer(WINDOW *win, int columns)
2935 wbkgd(win, A_REVERSE);
2938 wprintw(win, "footer: %d columns", columns);
2943 static int rip_header(WINDOW *win, int columns)
2945 wbkgd(win, A_REVERSE);
2948 wprintw(win, "header: %d columns", columns);
2953 /*+-------------------------------------------------------------------------
2955 --------------------------------------------------------------------------*/
2958 main(int argc, char *argv[])
2964 setlocale(LC_CTYPE, "");
2967 while ((c = getopt(argc, argv, "e:fhs:t:")) != EOF) {
2970 my_e_param = atoi(optarg);
2971 #ifdef NCURSES_VERSION
2972 if (my_e_param > 3) /* allow extended layouts */
2980 ripoffline(-1, rip_footer);
2983 ripoffline(1, rip_header);
2987 nap_msec = atol(optarg);
2992 save_trace = atoi(optarg);
3001 * If there's no menus (unlikely for ncurses!), then we'll have to set
3002 * tracing on initially, just in case the user wants to test something that
3003 * doesn't involve wGetchar.
3006 /* enable debugging */
3010 if (!isatty(fileno(stdin)))
3012 #endif /* USE_LIBMENU */
3015 /* tell it we're going to play with soft keys */
3016 slk_init(my_e_param);
3019 /* set up null signal catcher so we can see what interrupts to getch do */
3020 signal(SIGUSR1, announce_sig);
3023 /* we must initialize the curses data structure only once */
3027 /* tests, in general, will want these modes */
3029 set_terminal_modes();
3033 * Return to terminal mode, so we're guaranteed of being able to
3034 * select terminal commands even if the capabilities are wrong.
3038 (void) puts("Welcome to ncurses. Press ? for help.");
3041 (void) puts("This is the ncurses main menu");
3042 (void) puts("a = keyboard and mouse input test");
3043 (void) puts("b = character attribute test");
3044 (void) puts("c = color test pattern");
3045 (void) puts("d = edit RGB color values");
3046 (void) puts("e = exercise soft keys");
3047 (void) puts("f = display ACS characters");
3048 (void) puts("g = display windows and scrolling");
3049 (void) puts("i = test of flushinp()");
3050 (void) puts("k = display character attributes");
3052 (void) puts("m = menu code test");
3055 (void) puts("o = exercise panels library");
3056 (void) puts("p = exercise pad features");
3057 (void) puts("q = quit");
3060 (void) puts("r = exercise forms code");
3062 (void) puts("s = overlapping-refresh test");
3063 #if USE_LIBMENU && defined(TRACE)
3064 (void) puts("t = set trace level");
3066 (void) puts("? = repeat this command summary");
3068 (void) fputs("> ", stdout);
3069 (void) fflush(stdout); /* necessary under SVr4 curses */
3072 * This used to be an 'fgets()' call. However (on Linux, at least)
3073 * mixing stream I/O and 'read()' (used in the library) causes the
3074 * input stream to be flushed when switching between the two.
3079 if (read(fileno(stdin), &ch, 1) <= 0) {
3083 } else if (command == 0 && !isspace(ch)) {
3085 } else if (ch == '\n' || ch == '\r') {
3088 (void) fputs("> ", stdout);
3089 (void) fflush(stdout);
3093 if (do_single_test(command)) {
3095 * This may be overkill; it's intended to reset everything back
3096 * to the initial terminal modes so that tests don't get in
3100 set_terminal_modes();
3105 if (command == '?') {
3106 (void) puts("This is the ncurses capability tester.");
3107 (void) puts("You may select a test from the main menu by typing the");
3108 (void) puts("key letter of the choice (the letter to left of the =)");
3109 (void) puts("at the > prompt. The commands `x' or `q' will exit.");
3116 ExitProgram(EXIT_SUCCESS);
3119 /* ncurses.c ends here */