+ case 2:
+ if (!isspace(UChar(s[n])))
+ return FALSE;
+ break;
+ }
+ }
+
+ /* force the form to display a leading capital */
+ if (islower(UChar(s[0]))) {
+ s[0] = (char) toupper(UChar(s[0]));
+ set_field_buffer(fld, 0, s);
+ }
+ return TRUE;
+}
+
+static
+CHAR_CHECK_CB(mi_char_check)
+{
+ return ((isalpha(ch) || ch == '.') ? TRUE : FALSE);
+}
+
+/*
+ * Passwords should be at least 6 characters.
+ */
+static
+FIELDCHECK_CB(pw_field_check)
+{
+ char *s = field_buffer(fld, 0);
+ int n;
+
+ for (n = 0; s[n] != '\0'; ++n) {
+ if (isspace(UChar(s[n]))) {
+ if (n < 6)
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static
+CHAR_CHECK_CB(pw_char_check)
+{
+ return (isgraph(ch) ? TRUE : FALSE);
+}
+
+static int
+form_test(bool recur GCC_UNUSED)
+{
+ WINDOW *w;
+ FORM *form;
+ FIELD *f[12], *secure;
+ FIELDTYPE *fty_middle = new_fieldtype(mi_field_check, mi_char_check);
+ FIELDTYPE *fty_passwd = new_fieldtype(pw_field_check, pw_char_check);
+ int finished = 0, c;
+ unsigned n = 0;
+
+#ifdef NCURSES_MOUSE_VERSION
+ mousemask(ALL_MOUSE_EVENTS, (mmask_t *) 0);
+#endif
+
+ move(18, 0);
+ addstr("Defined edit/traversal keys: ^Q/ESC- exit form\n");
+ addstr("^N -- go to next field ^P -- go to previous field\n");
+ addstr("Home -- go to first field End -- go to last field\n");
+ addstr("^L -- go to field to left ^R -- go to field to right\n");
+ addstr("^U -- move upward to field ^D -- move downward to field\n");
+ addstr("^W -- go to next word ^B -- go to previous word\n");
+ addstr("^S -- go to start of field ^E -- go to end of field\n");
+ addstr("^H -- delete previous char ^Y -- delete line\n");
+ addstr("^G -- delete current word ^C -- clear to end of line\n");
+ addstr("^K -- clear to end of field ^X -- clear field\n");
+ addstr("Arrow keys move within a field as you would expect. ^] toggles overlay mode.");
+
+ MvAddStr(4, 57, "Forms Entry Test");
+
+ refresh();
+
+ /* describe the form */
+ memset(f, 0, sizeof(f));
+ f[n++] = make_label(0, 15, "Sample Form");
+
+ f[n++] = make_label(2, 0, "Last Name");
+ f[n++] = make_field(3, 0, 1, 18, FALSE);
+ set_field_type(f[n - 1], TYPE_ALPHA, 1);
+
+ f[n++] = make_label(2, 20, "First Name");
+ f[n++] = make_field(3, 20, 1, 12, FALSE);
+ set_field_type(f[n - 1], TYPE_ALPHA, 1);
+
+ f[n++] = make_label(2, 34, "Middle Name");
+ f[n++] = make_field(3, 34, 1, 12, FALSE);
+ set_field_type(f[n - 1], fty_middle);
+
+ f[n++] = make_label(5, 0, "Comments");
+ f[n++] = make_field(6, 0, 4, 46, FALSE);
+
+ f[n++] = make_label(5, 20, "Password:");
+ secure =
+ f[n++] = make_field(5, 30, 1, 9, TRUE);
+ set_field_type(f[n - 1], fty_passwd);
+ f[n] = (FIELD *) 0;
+
+ if ((form = new_form(f)) != 0) {
+
+ display_form(form);
+
+ w = form_win(form);
+ raw();
+ nonl(); /* lets us read ^M's */
+ while (!finished) {
+ switch (form_driver(form, c = form_virtualize(form, w))) {
+ case E_OK:
+ MvAddStr(5, 57, field_buffer(secure, 1));
+ clrtoeol();
+ refresh();
+ break;
+ case E_UNKNOWN_COMMAND:
+ finished = my_form_driver(form, c);
+ break;
+ default:
+ beep();
+ break;
+ }
+ }
+
+ erase_form(form);
+
+ free_form(form);
+ }
+ for (c = 0; f[c] != 0; c++)
+ free_field(f[c]);
+ free_fieldtype(fty_middle);
+ free_fieldtype(fty_passwd);
+ noraw();
+ nl();
+
+#ifdef NCURSES_MOUSE_VERSION
+ mousemask(ALL_MOUSE_EVENTS, (mmask_t *) 0);
+#endif
+ return OK;
+}
+#endif /* USE_LIBFORM */
+
+/****************************************************************************
+ *
+ * Overlap test
+ *
+ ****************************************************************************/
+
+#if HAVE_COPYWIN /* ...and overlay, overwrite */
+
+static const int overlap_HEAD = 1;
+static const int overlap_FOOT = 6;
+
+static WINDOW *
+make_overlap(int n)
+{
+ WINDOW *result;
+ int y, x;
+
+ getmaxyx(stdscr, y, x);
+ if (y < 23 || x < 80) {
+ Cannot("The screen is too small for this test");
+ result = 0;
+ } else {
+ int ymax = y - (overlap_HEAD + overlap_FOOT);
+ int high = ymax / 5; /* equal-sized parts for cross */
+ int xmax = x - 2; /* margin */
+ int wide = (xmax / 5) & ~1;
+ int lmar, tmar;
+
+ if (high > 8)
+ high = 8;
+
+ if (wide > 8)
+ wide = 8;
+
+ tmar = (ymax - (5 * high)) / 2 + overlap_HEAD;
+ lmar = (xmax - (5 * wide)) / 2;
+
+ if (n == 0) {
+ result = newwin(3 * high, 3 * wide, tmar, lmar);
+ } else {
+ result = newwin(3 * high, 3 * wide, tmar + 2 * high, lmar + 2 * wide);
+ }
+ }
+ return result;
+}
+
+static void
+clear_overlap(void)
+{
+ int row;
+
+ for (row = overlap_HEAD; row < LINES - overlap_FOOT; ++row) {
+ move(row, 0);
+ clrtoeol();
+ }
+}
+
+static int
+move_overlap(int shift, WINDOW *win1)
+{
+ int ymax = getmaxy(stdscr) - (overlap_HEAD + overlap_FOOT);
+ int high = ymax / 5; /* equal-sized parts for cross */
+ int tmar;
+ int xmax1 = getmaxx(win1) + 1;
+ int lmar1 = (COLS - (5 * (xmax1) / 3)) / 2;
+ int rc = ERR;
+
+ if (high > 8)
+ high = 8;
+ tmar = (ymax - (5 * high)) / 2 + overlap_HEAD;
+
+ rc = mvwin(win1, tmar, lmar1 + shift);
+ return rc;
+}
+
+static void
+fillwin(WINDOW *win, char ch)
+{
+ int y, x;
+ int y1, x1;
+
+ getmaxyx(win, y1, x1);
+ for (y = 0; y < y1; y++) {
+ wmove(win, y, 0);
+ for (x = 0; x < x1; x++)
+ waddch(win, UChar(ch));
+ }
+}
+
+#define InCross(x,y, x1,y1) \
+ (((x > (x1 - 1) / 3) && (x <= (2 * (x1 - 1)) / 3)) \
+ || (((y > (y1 - 1) / 3) && (y <= (2 * (y1 - 1)) / 3))))
+
+static void
+crosswin(WINDOW *win, char ch)
+{
+ int y, x;
+ int y1, x1;
+ int xw = 1;
+
+ getmaxyx(win, y1, x1);
+ for (y = 0; y < y1; y++) {
+ for (x = 0; x < x1; x += xw) {
+ if (InCross(x, y, x1, y1)) {
+ wmove(win, y, x);
+ waddch(win, UChar(ch));
+ }
+ }
+ }
+}
+
+/*
+ * Match "crosswin()", but using line-drawing characters. This could be done
+ * a little simpler using box(), but the reason for this example is to test
+ * hline/vline and addch with line-drawing vs the copy/overlay functions.
+ */
+static void
+crossbox(WINDOW *win)
+{
+ int y1, x1;
+ int ymax, xmax;
+
+ getmaxyx(win, y1, x1);
+
+ ymax = (y1 + 1);
+ xmax = (x1 + 1);
+
+ mvwhline(win, 0, (xmax / 3), ACS_HLINE, (xmax / 3));
+ mvwhline(win, ymax / 3, 0, ACS_HLINE, xmax);
+ mvwhline(win, ((2 * ymax) / 3) - 1, 0, ACS_HLINE, xmax);
+ mvwhline(win, y1 - 1, (xmax / 3), ACS_HLINE, (xmax / 3));
+
+ mvwvline(win, (ymax / 3), 0, ACS_VLINE, (ymax / 3));
+ mvwvline(win, 0, xmax / 3, ACS_VLINE, ymax);
+ mvwvline(win, 0, ((2 * xmax) / 3) - 1, ACS_VLINE, ymax);
+ mvwvline(win, (ymax / 3), x1 - 1, ACS_VLINE, (ymax / 3));
+
+ mvwaddch(win, 0, (xmax / 3), ACS_ULCORNER);
+ mvwaddch(win, 0, ((2 * xmax) / 3) - 1, ACS_URCORNER);
+ mvwaddch(win, y1 - 1, (xmax / 3), ACS_LLCORNER);
+ mvwaddch(win, y1 - 1, ((2 * xmax) / 3) - 1, ACS_LRCORNER);
+
+ mvwaddch(win, (ymax / 3), 0, ACS_ULCORNER);
+ mvwaddch(win, ((2 * ymax) / 3) - 1, 0, ACS_LLCORNER);
+ mvwaddch(win, (ymax / 3), x1 - 1, ACS_URCORNER);
+ mvwaddch(win, ((2 * ymax) / 3) - 1, x1 - 1, ACS_LRCORNER);
+
+ mvwaddch(win, (ymax / 3), (xmax / 3), ACS_PLUS);
+ mvwaddch(win, (ymax / 3), ((2 * xmax) / 3) - 1, ACS_PLUS);
+ mvwaddch(win, ((2 * ymax) / 3) - 1, ((2 * xmax) / 3) - 1, ACS_PLUS);
+ mvwaddch(win, ((2 * ymax) / 3) - 1, (xmax / 3), ACS_PLUS);
+}
+
+typedef enum {
+ otBASE_refresh = 0
+ ,otBASE_fill
+ ,otBASE_draw
+ ,otBASE_clear
+ ,otBASE_copy
+} otBASE;
+
+#define OVERLAP_FLAVORS 6
+
+typedef enum {
+ otFILL_normal = 0
+ ,otFILL_bold
+ ,otFILL_color
+ ,otFILL_bright
+} otFILL;
+
+#define LimitFILL() UseColors ? 4 : 2
+
+typedef enum {
+ otDRAW_text_cross = 0
+ ,otDRAW_line_box
+ ,otDRAW_line_cross
+ ,otDRAW_set_bg
+ ,otDRAW_reset_bg
+} otDRAW;
+
+#define LimitDRAW() UseColors ? 5 : 3
+
+typedef enum {
+ otCOPY_overwrite = 0
+ ,otCOPY_merge
+ ,otCOPY_force
+ ,otCOPY_overlay
+} otCOPY;
+
+#define LimitCOPY() 4
+
+static void
+overlap_helpitem(int state, int item, char *message)
+{
+ int row = (item / 2);
+ int col = ((item % 2) ? COLS / 2 : 0);
+
+ move(LINES - 6 + row, col);
+ printw("%c%c = %s", state == row ? '>' : ' ', 'a' + item, message);
+ clrtoeol();
+}
+
+static void
+overlap_test_1_attr(WINDOW *win, int flavor, int col)
+{
+ NCURSES_PAIRS_T cpair = (NCURSES_PAIRS_T) (1 + (flavor * 2) + col);
+
+ switch ((otFILL) flavor) {
+ case otFILL_normal:
+ (void) wattrset(win, A_NORMAL);
+ break;
+ case otFILL_bold:
+ (void) wattrset(win, A_BOLD);
+ break;
+ case otFILL_color:
+ init_pair(cpair, COLOR_BLUE, COLOR_WHITE);
+ (void) wattrset(win, AttrArg(COLOR_PAIR(cpair), A_NORMAL));
+ break;
+ case otFILL_bright:
+ init_pair(cpair, COLOR_WHITE, COLOR_BLUE);
+ (void) wattrset(win, AttrArg(COLOR_PAIR(cpair), A_BOLD));
+ break;
+ }
+}
+
+static void
+overlap_test_2_attr(WINDOW *win, int flavor, int col)
+{
+ NCURSES_PAIRS_T cpair = (NCURSES_PAIRS_T) (9 + (flavor * 2) + col);
+
+ switch ((otDRAW) flavor) {
+ case otDRAW_text_cross:
+ /* no effect */
+ break;
+ case otDRAW_line_box:
+ /* no effect */
+ break;
+ case otDRAW_line_cross:
+ /* no effect */
+ break;
+ case otDRAW_set_bg:
+ init_pair(cpair, COLOR_RED, COLOR_GREEN);
+ wbkgdset(win, colored_chtype(' ', A_BLINK, cpair));
+ break;
+ case otDRAW_reset_bg:
+ wbkgdset(win, ' ' | A_NORMAL);
+ break;
+ }
+}
+
+static int
+overlap_help(int state, int flavors[OVERLAP_FLAVORS])
+{
+ int row;
+ int col;
+ int item;
+ int limit[OVERLAP_FLAVORS];
+ const char *ths, *tht;
+ char msg[80];
+
+ if (state < 0)
+ state += OVERLAP_FLAVORS;
+ state = state % OVERLAP_FLAVORS;
+ assert(state >= 0 && state < OVERLAP_FLAVORS);
+
+ for (item = 0; item < (2 * OVERLAP_FLAVORS); ++item) {
+ row = item / 2;
+ col = item % 2;
+ ths = col ? "B" : "A";
+ tht = col ? "A" : "B";
+
+ switch ((otBASE) row) {
+ case otBASE_refresh:
+ limit[row] = 1;
+ flavors[row] = 0;
+ _nc_SPRINTF(msg, _nc_SLIMIT(sizeof(msg))
+ "refresh %s, then %s, then doupdate.", ths, tht);
+ break;
+ case otBASE_fill:
+ limit[row] = LimitFILL();
+ flavors[row] %= limit[row];
+ overlap_test_1_attr(stdscr, flavors[row], col);
+ _nc_SPRINTF(msg, _nc_SLIMIT(sizeof(msg))
+ "fill window %s with letter %s.", ths, ths);
+ break;
+ case otBASE_draw:
+ limit[row] = LimitDRAW();
+ flavors[row] %= limit[row];
+ switch ((otDRAW) flavors[row]) {
+ case otDRAW_text_cross:
+ _nc_SPRINTF(msg, _nc_SLIMIT(sizeof(msg))
+ "cross text-pattern in window %s.", ths);
+ break;
+ case otDRAW_line_box:
+ _nc_SPRINTF(msg, _nc_SLIMIT(sizeof(msg))
+ "draw line-box in window %s.", ths);
+ break;
+ case otDRAW_line_cross:
+ _nc_SPRINTF(msg, _nc_SLIMIT(sizeof(msg))
+ "draw line-cross in window %s.", ths);
+ break;
+ case otDRAW_set_bg:
+ _nc_SPRINTF(msg, _nc_SLIMIT(sizeof(msg))
+ "set background of window %s.", ths);
+ break;
+ case otDRAW_reset_bg:
+ _nc_SPRINTF(msg, _nc_SLIMIT(sizeof(msg))
+ "reset background of window %s.", ths);
+ break;
+ }
+ break;
+ case otBASE_clear:
+ limit[row] = 1;
+ flavors[row] = 0;
+ _nc_SPRINTF(msg, _nc_SLIMIT(sizeof(msg))
+ "clear window %s.", ths);
+ break;
+ case otBASE_copy:
+ limit[row] = LimitCOPY();
+ flavors[row] %= limit[row];
+ switch ((otCOPY) flavors[row]) {
+ case otCOPY_overwrite:
+ _nc_SPRINTF(msg, _nc_SLIMIT(sizeof(msg))
+ "overwrite %s onto %s.", ths, tht);
+ break;
+ case otCOPY_merge:
+ _nc_SPRINTF(msg, _nc_SLIMIT(sizeof(msg))
+ "copywin(FALSE) %s onto %s.", ths, tht);
+ break;
+ case otCOPY_force:
+ _nc_SPRINTF(msg, _nc_SLIMIT(sizeof(msg))
+ "copywin(TRUE) %s onto %s.", ths, tht);
+ break;
+ case otCOPY_overlay:
+ _nc_SPRINTF(msg, _nc_SLIMIT(sizeof(msg))
+ "overlay %s onto %s.", ths, tht);
+ break;
+ }