+/****************************************************************************
+ *
+ * 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;
+ }
+ break;
+ }
+ overlap_helpitem(state, item, msg);
+ (void) wattrset(stdscr, A_NORMAL);
+ wbkgdset(stdscr, ' ' | A_NORMAL);
+ }
+ move(LINES - 1, 0);
+ printw("^Q/ESC = terminate test. </> shift. Up/down/space select (row %d",
+ state + 1);
+ if (limit[state] > 1)
+ printw(" test %d:%d", 1 + flavors[state], limit[state]);
+ printw(").");
+ clrtoeol();
+
+ return state;
+}
+
+static void
+overlap_test_0(WINDOW *a, WINDOW *b)
+{
+ touchwin(a);
+ touchwin(b);
+ wnoutrefresh(a);
+ wnoutrefresh(b);
+ doupdate();
+}
+
+static void
+overlap_test_1(int flavor, int col, WINDOW *a, char fill)
+{
+ overlap_test_1_attr(a, flavor, col);
+ fillwin(a, fill);
+ (void) wattrset(a, A_NORMAL);
+}
+
+static void
+overlap_test_2(int flavor, int col, WINDOW *a, char fill)
+{
+ overlap_test_2_attr(a, flavor, col);
+ switch ((otDRAW) flavor) {
+ case otDRAW_text_cross:
+ crosswin(a, fill);
+ break;
+ case otDRAW_line_box:
+ box(a, 0, 0);
+ break;
+ case otDRAW_line_cross:
+ crossbox(a);
+ break;
+ case otDRAW_set_bg:
+ /* done in overlap_test_2_attr */
+ break;
+ case otDRAW_reset_bg:
+ /* done in overlap_test_2_attr */
+ break;
+ }
+}
+
+static void
+overlap_test_3(WINDOW *a)
+{
+ wclear(a);
+ wmove(a, 0, 0);
+}
+
+static void
+overlap_test_4(int flavor, WINDOW *a, WINDOW *b)
+{
+ switch ((otCOPY) flavor) {
+ case otCOPY_overwrite:
+ overwrite(a, b);
+ break;
+ case otCOPY_merge:
+ copywin(a, b, 0, 0, 0, 0, getmaxy(b), getmaxx(b), FALSE);
+ break;
+ case otCOPY_force:
+ copywin(a, b, 0, 0, 0, 0, getmaxy(b), getmaxx(b), TRUE);
+ break;
+ case otCOPY_overlay:
+ overlay(a, b);
+ break;
+ }
+}
+
+/* test effects of overlapping windows */
+static int
+overlap_test(bool recur GCC_UNUSED)
+{
+ WINDOW *win1, *win2;
+ int ch;
+ int shift = 0, last_refresh = -1;
+ int state, flavor[OVERLAP_FLAVORS];
+
+ if ((win1 = make_overlap(0)) == 0
+ || (win2 = make_overlap(1)) == 0)
+ return ERR;
+
+ curs_set(0);
+ raw();
+ refresh();
+ move(0, 0);
+ printw("Test wnoutrefresh() for two overlapping windows:");
+
+ memset(flavor, 0, sizeof(flavor));
+ state = overlap_help(0, flavor);
+
+ while (!isQuit(ch = Getchar(), TRUE)) {
+ switch (ch) {
+ case 'a': /* refresh window A first, then B */
+ overlap_test_0(win1, win2);
+ break;
+
+ case 'b': /* refresh window B first, then A */
+ overlap_test_0(win2, win1);
+ break;
+
+ case 'c': /* fill window A so it's visible */
+ overlap_test_1(flavor[otBASE_fill], 0, win1, 'A');
+ break;
+
+ case 'd': /* fill window B so it's visible */
+ overlap_test_1(flavor[otBASE_fill], 1, win2, 'B');
+ break;
+
+ case 'e': /* cross test pattern in window A */
+ overlap_test_2(flavor[otBASE_draw], 0, win1, 'A');
+ break;
+
+ case 'f': /* cross test pattern in window A */
+ overlap_test_2(flavor[otBASE_draw], 1, win2, 'B');
+ break;
+
+ case 'g': /* clear window A */
+ overlap_test_3(win1);
+ break;
+
+ case 'h': /* clear window B */
+ overlap_test_3(win2);
+ break;
+
+ case 'i': /* overwrite A onto B */
+ overlap_test_4(flavor[otBASE_copy], win1, win2);
+ break;
+
+ case 'j': /* overwrite B onto A */
+ overlap_test_4(flavor[otBASE_copy], win2, win1);
+ break;
+
+ case CTRL('n'):
+ case KEY_DOWN:
+ state = overlap_help(state + 1, flavor);
+ break;
+
+ case CTRL('p'):
+ case KEY_UP:
+ state = overlap_help(state - 1, flavor);
+ break;
+
+ case ' ':
+ flavor[state] += 1;
+ state = overlap_help(state, flavor);
+ break;
+
+ case HELP_KEY_1:
+ state = overlap_help(state, flavor);
+ break;
+
+ case '<':
+ /* FALLTHRU */
+ case '>':
+ /* see below */
+ break;
+
+ default:
+ beep();
+ break;
+ }
+
+ switch (ch) {
+ case 'a':
+ /* FALLTHRU */
+ case 'b':
+ last_refresh = ch;
+ break;
+ case '<':
+ shift -= 2;
+ /* FALLTHRU */
+ case '>':
+ shift += 1;
+ if (move_overlap(shift, win1) != OK) {
+ flash();
+ shift += (ch == '>') ? -1 : 1;
+ } else if (last_refresh > 0) {
+ clear_overlap();
+ wnoutrefresh(stdscr);
+ if (last_refresh == 'a')
+ overlap_test_0(win1, win2);
+ else
+ overlap_test_0(win2, win1);
+ }
+ break;
+ default:
+ last_refresh = -1;
+ break;
+ }
+ }
+
+ delwin(win2);
+ delwin(win1);
+ erase();
+ exit_curses();
+ return OK;
+}