missing ncurses sources
[tomato.git] / release / src / router / libncurses / test / ncurses.c
blob5a422cf1a8cd5f92f7dbb048f3a7c3749e551e27
1 /****************************************************************************
2 * Copyright (c) 1998-2010,2011 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.365 2011/01/22 19:48:33 tom Exp $
45 ***************************************************************************/
47 #include <test.priv.h>
49 #ifdef __hpux
50 #undef mvwdelch /* HPUX 11.23 macro will not compile */
51 #endif
53 #if HAVE_GETTIMEOFDAY
54 #if HAVE_SYS_TIME_H && HAVE_SYS_TIME_SELECT
55 #include <sys/time.h>
56 #endif
57 #if HAVE_SYS_SELECT_H
58 #include <sys/select.h>
59 #endif
60 #endif
62 #if USE_LIBPANEL
63 #include <panel.h>
64 #endif
66 #if USE_LIBMENU
67 #include <menu.h>
68 #endif
70 #if USE_LIBFORM
71 #include <form.h>
72 #endif
74 #ifdef NCURSES_VERSION
76 #define NCURSES_CONST_PARAM const void
78 #ifdef TRACE
79 static unsigned save_trace = TRACE_ORDINARY | TRACE_ICALLS | TRACE_CALLS;
80 extern unsigned _nc_tracing;
81 #endif
83 #else
85 #define NCURSES_CONST_PARAM char
87 #define mmask_t chtype /* not specified in XSI */
89 #ifndef ACS_S3
90 #ifdef CURSES_ACS_ARRAY
91 #define ACS_S3 (CURSES_ACS_ARRAY['p']) /* scan line 3 */
92 #define ACS_S7 (CURSES_ACS_ARRAY['r']) /* scan line 7 */
93 #define ACS_LEQUAL (CURSES_ACS_ARRAY['y']) /* less/equal */
94 #define ACS_GEQUAL (CURSES_ACS_ARRAY['z']) /* greater/equal */
95 #define ACS_PI (CURSES_ACS_ARRAY['{']) /* Pi */
96 #define ACS_NEQUAL (CURSES_ACS_ARRAY['|']) /* not equal */
97 #define ACS_STERLING (CURSES_ACS_ARRAY['}']) /* UK pound sign */
98 #else
99 #define ACS_S3 (A_ALTCHARSET + 'p') /* scan line 3 */
100 #define ACS_S7 (A_ALTCHARSET + 'r') /* scan line 7 */
101 #define ACS_LEQUAL (A_ALTCHARSET + 'y') /* less/equal */
102 #define ACS_GEQUAL (A_ALTCHARSET + 'z') /* greater/equal */
103 #define ACS_PI (A_ALTCHARSET + '{') /* Pi */
104 #define ACS_NEQUAL (A_ALTCHARSET + '|') /* not equal */
105 #define ACS_STERLING (A_ALTCHARSET + '}') /* UK pound sign */
106 #endif
107 #endif /* ACS_S3 */
109 #ifndef WACS_S3
110 #ifdef CURSES_WACS_ARRAY
111 #define WACS_S3 (&(CURSES_WACS_ARRAY['p'])) /* scan line 3 */
112 #define WACS_S7 (&(CURSES_WACS_ARRAY['r'])) /* scan line 7 */
113 #define WACS_LEQUAL (&(CURSES_WACS_ARRAY['y'])) /* less/equal */
114 #define WACS_GEQUAL (&(CURSES_WACS_ARRAY['z'])) /* greater/equal */
115 #define WACS_PI (&(CURSES_WACS_ARRAY['{'])) /* Pi */
116 #define WACS_NEQUAL (&(CURSES_WACS_ARRAY['|'])) /* not equal */
117 #define WACS_STERLING (&(CURSES_WACS_ARRAY['}'])) /* UK pound sign */
118 #endif
119 #endif
121 #endif
123 #if HAVE_WCSRTOMBS
124 #define count_wchars(src, len, state) wcsrtombs(0, &src, len, state)
125 #define trans_wchars(dst, src, len, state) wcsrtombs(dst, &src, len, state)
126 #define reset_wchars(state) init_mb(state)
127 #elif HAVE_WCSTOMBS && HAVE_MBTOWC && HAVE_MBLEN
128 #define count_wchars(src, len, state) wcstombs(0, src, len)
129 #define trans_wchars(dst, src, len, state) wcstombs(dst, src, len)
130 #define reset_wchars(state) IGNORE_RC(mblen(NULL, 0)), IGNORE_RC(mbtowc(NULL, NULL, 0))
131 #define state_unused
132 #endif
134 #if HAVE_MBSRTOWCS
135 #define count_mbytes(src, len, state) mbsrtowcs(0, &src, len, state)
136 #define trans_mbytes(dst, src, len, state) mbsrtowcs(dst, &src, len, state)
137 #define reset_mbytes(state) init_mb(state)
138 #elif HAVE_MBSTOWCS && HAVE_MBTOWC && HAVE_MBLEN
139 #define count_mbytes(src, len, state) mbstowcs(0, src, len)
140 #define trans_mbytes(dst, src, len, state) mbstowcs(dst, src, len)
141 #define reset_mbytes(state) IGNORE_RC(mblen(NULL, 0)), IGNORE_RC(mbtowc(NULL, NULL, 0))
142 #define state_unused
143 #endif
145 #define ToggleAcs(temp,real) temp = ((temp == real) ? 0 : real)
147 #define P(string) printw("%s\n", string)
149 #define BLANK ' ' /* this is the background character */
151 #undef max_colors
152 static int max_colors; /* the actual number of colors we'll use */
153 static int min_colors; /* the minimum color code */
154 static bool use_colors; /* true if we use colors */
156 #undef max_pairs
157 static int max_pairs; /* ...and the number of color pairs */
159 typedef struct {
160 short red;
161 short green;
162 short blue;
163 } RGB_DATA;
165 static RGB_DATA *all_colors;
167 static void main_menu(bool);
169 /* The behavior of mvhline, mvvline for negative/zero length is unspecified,
170 * though we can rely on negative x/y values to stop the macro.
172 static void
173 do_h_line(int y, int x, chtype c, int to)
175 if ((to) > (x))
176 MvHLine(y, x, c, (to) - (x));
179 static void
180 do_v_line(int y, int x, chtype c, int to)
182 if ((to) > (y))
183 MvVLine(y, x, c, (to) - (y));
186 static void
187 Repaint(void)
189 touchwin(stdscr);
190 touchwin(curscr);
191 wrefresh(curscr);
194 static bool
195 isQuit(int c)
197 return ((c) == QUIT || (c) == ESCAPE);
199 #define case_QUIT QUIT: case ESCAPE
201 /* Common function to allow ^T to toggle trace-mode in the middle of a test
202 * so that trace-files can be made smaller.
204 static int
205 wGetchar(WINDOW *win)
207 int c;
208 #ifdef TRACE
209 while ((c = wgetch(win)) == CTRL('T')) {
210 if (_nc_tracing) {
211 save_trace = _nc_tracing;
212 Trace(("TOGGLE-TRACING OFF"));
213 _nc_tracing = 0;
214 } else {
215 _nc_tracing = save_trace;
217 trace(_nc_tracing);
218 if (_nc_tracing)
219 Trace(("TOGGLE-TRACING ON"));
221 #else
222 c = wgetch(win);
223 #endif
224 return c;
226 #define Getchar() wGetchar(stdscr)
228 /* replaces wgetnstr(), since we want to be able to edit values */
229 static void
230 wGetstring(WINDOW *win, char *buffer, int limit)
232 int y0, x0, x, ch;
233 bool done = FALSE;
235 echo();
236 getyx(win, y0, x0);
237 (void) wattrset(win, A_REVERSE);
239 x = (int) strlen(buffer);
240 while (!done) {
241 if (x > (int) strlen(buffer))
242 x = (int) strlen(buffer);
243 wmove(win, y0, x0);
244 wprintw(win, "%-*s", limit, buffer);
245 wmove(win, y0, x0 + x);
246 switch (ch = wGetchar(win)) {
247 case '\n':
248 case KEY_ENTER:
249 done = TRUE;
250 break;
251 case CTRL('U'):
252 *buffer = '\0';
253 break;
254 case '\b':
255 case KEY_BACKSPACE:
256 case KEY_DC:
257 if (x > 0) {
258 int j;
259 for (j = --x; (buffer[j] = buffer[j + 1]) != '\0'; ++j) {
262 } else {
263 beep();
265 break;
266 case KEY_LEFT:
267 if (x > 0) {
268 --x;
269 } else {
270 flash();
272 break;
273 case KEY_RIGHT:
274 ++x;
275 break;
276 default:
277 if (!isprint(ch) || ch >= KEY_MIN) {
278 beep();
279 } else if ((int) strlen(buffer) < limit) {
280 int j;
281 for (j = (int) strlen(buffer) + 1; j > x; --j) {
282 buffer[j] = buffer[j - 1];
284 buffer[x++] = (char) ch;
285 } else {
286 flash();
291 wattroff(win, A_REVERSE);
292 wmove(win, y0, x0);
293 noecho();
296 #if USE_WIDEC_SUPPORT
297 static wchar_t
298 fullwidth_of(int ch)
300 return (ch + 0xff10 - '0');
303 static void
304 make_fullwidth_text(wchar_t *target, const char *source)
306 int ch;
307 while ((ch = *source++) != 0) {
308 *target++ = fullwidth_of(ch);
310 *target = 0;
313 static void
314 make_narrow_text(wchar_t *target, const char *source)
316 int ch;
317 while ((ch = *source++) != 0) {
318 *target++ = ch;
320 *target = 0;
323 #if USE_LIBPANEL
324 static void
325 make_fullwidth_digit(cchar_t *target, int digit)
327 wchar_t source[2];
329 source[0] = fullwidth_of(digit + '0');
330 source[1] = 0;
331 setcchar(target, source, A_NORMAL, 0, 0);
333 #endif
335 static int
336 wGet_wchar(WINDOW *win, wint_t *result)
338 int c;
339 #ifdef TRACE
340 while ((c = wget_wch(win, result)) == CTRL('T')) {
341 if (_nc_tracing) {
342 save_trace = _nc_tracing;
343 Trace(("TOGGLE-TRACING OFF"));
344 _nc_tracing = 0;
345 } else {
346 _nc_tracing = save_trace;
348 trace(_nc_tracing);
349 if (_nc_tracing)
350 Trace(("TOGGLE-TRACING ON"));
352 #else
353 c = wget_wch(win, result);
354 #endif
355 return c;
357 #define Get_wchar(result) wGet_wchar(stdscr, result)
359 /* replaces wgetn_wstr(), since we want to be able to edit values */
360 static void
361 wGet_wstring(WINDOW *win, wchar_t *buffer, int limit)
363 int y0, x0, x;
364 wint_t ch;
365 bool done = FALSE;
366 bool fkey = FALSE;
368 echo();
369 getyx(win, y0, x0);
370 (void) wattrset(win, A_REVERSE);
372 x = (int) wcslen(buffer);
373 while (!done) {
374 if (x > (int) wcslen(buffer))
375 x = (int) wcslen(buffer);
377 /* clear the "window' */
378 wmove(win, y0, x0);
379 wprintw(win, "%*s", limit, " ");
381 /* write the existing buffer contents */
382 wmove(win, y0, x0);
383 waddnwstr(win, buffer, limit);
385 /* positions the cursor past character 'x' */
386 wmove(win, y0, x0);
387 waddnwstr(win, buffer, x);
389 switch (wGet_wchar(win, &ch)) {
390 case KEY_CODE_YES:
391 fkey = TRUE;
392 switch (ch) {
393 case KEY_ENTER:
394 ch = '\n';
395 fkey = FALSE;
396 break;
397 case KEY_BACKSPACE:
398 case KEY_DC:
399 ch = '\b';
400 fkey = FALSE;
401 break;
402 case KEY_LEFT:
403 case KEY_RIGHT:
404 break;
405 default:
406 ch = (wint_t) -1;
407 break;
409 break;
410 case OK:
411 fkey = FALSE;
412 break;
413 default:
414 ch = (wint_t) -1;
415 fkey = TRUE;
416 break;
419 switch (ch) {
420 case '\n':
421 done = TRUE;
422 break;
423 case CTRL('U'):
424 *buffer = '\0';
425 break;
426 case '\b':
427 if (x > 0) {
428 int j;
429 for (j = --x; (buffer[j] = buffer[j + 1]) != '\0'; ++j) {
432 } else {
433 beep();
435 break;
436 case KEY_LEFT:
437 if (x > 0) {
438 --x;
439 } else {
440 beep();
442 break;
443 case KEY_RIGHT:
444 ++x;
445 break;
446 default:
447 if (fkey) {
448 beep();
449 } else if ((int) wcslen(buffer) < limit) {
450 int j;
451 for (j = (int) wcslen(buffer) + 1; j > x; --j) {
452 buffer[j] = buffer[j - 1];
454 buffer[x++] = (wchar_t) ch;
455 } else {
456 beep();
461 wattroff(win, A_REVERSE);
462 wmove(win, y0, x0);
463 noecho();
466 #endif
468 static void
469 Pause(void)
471 move(LINES - 1, 0);
472 addstr("Press any key to continue... ");
473 (void) Getchar();
476 static void
477 Cannot(const char *what)
479 printw("\nThis %s terminal %s\n\n", getenv("TERM"), what);
480 Pause();
483 static void
484 ShellOut(bool message)
486 if (message)
487 addstr("Shelling out...");
488 def_prog_mode();
489 endwin();
490 #ifdef __MINGW32__
491 system("cmd.exe");
492 #else
493 system("sh");
494 #endif
495 if (message)
496 addstr("returned from shellout.\n");
497 refresh();
500 #ifdef NCURSES_MOUSE_VERSION
502 * This function is the same as _tracemouse(), but we cannot count on that
503 * being available in the non-debug library.
505 static const char *
506 mouse_decode(MEVENT const *ep)
508 static char buf[80 + (5 * 10) + (32 * 15)];
510 (void) sprintf(buf, "id %2d at (%2d, %2d, %d) state %4lx = {",
511 ep->id, ep->x, ep->y, ep->z, (unsigned long) ep->bstate);
513 #define SHOW(m, s) if ((ep->bstate & m)==m) {strcat(buf,s); strcat(buf, ", ");}
515 SHOW(BUTTON1_RELEASED, "release-1");
516 SHOW(BUTTON1_PRESSED, "press-1");
517 SHOW(BUTTON1_CLICKED, "click-1");
518 SHOW(BUTTON1_DOUBLE_CLICKED, "doubleclick-1");
519 SHOW(BUTTON1_TRIPLE_CLICKED, "tripleclick-1");
520 #if NCURSES_MOUSE_VERSION == 1
521 SHOW(BUTTON1_RESERVED_EVENT, "reserved-1");
522 #endif
524 SHOW(BUTTON2_RELEASED, "release-2");
525 SHOW(BUTTON2_PRESSED, "press-2");
526 SHOW(BUTTON2_CLICKED, "click-2");
527 SHOW(BUTTON2_DOUBLE_CLICKED, "doubleclick-2");
528 SHOW(BUTTON2_TRIPLE_CLICKED, "tripleclick-2");
529 #if NCURSES_MOUSE_VERSION == 1
530 SHOW(BUTTON2_RESERVED_EVENT, "reserved-2");
531 #endif
533 SHOW(BUTTON3_RELEASED, "release-3");
534 SHOW(BUTTON3_PRESSED, "press-3");
535 SHOW(BUTTON3_CLICKED, "click-3");
536 SHOW(BUTTON3_DOUBLE_CLICKED, "doubleclick-3");
537 SHOW(BUTTON3_TRIPLE_CLICKED, "tripleclick-3");
538 #if NCURSES_MOUSE_VERSION == 1
539 SHOW(BUTTON3_RESERVED_EVENT, "reserved-3");
540 #endif
542 SHOW(BUTTON4_RELEASED, "release-4");
543 SHOW(BUTTON4_PRESSED, "press-4");
544 SHOW(BUTTON4_CLICKED, "click-4");
545 SHOW(BUTTON4_DOUBLE_CLICKED, "doubleclick-4");
546 SHOW(BUTTON4_TRIPLE_CLICKED, "tripleclick-4");
547 #if NCURSES_MOUSE_VERSION == 1
548 SHOW(BUTTON4_RESERVED_EVENT, "reserved-4");
549 #endif
551 #if NCURSES_MOUSE_VERSION == 2
552 SHOW(BUTTON5_RELEASED, "release-5");
553 SHOW(BUTTON5_PRESSED, "press-5");
554 SHOW(BUTTON5_CLICKED, "click-5");
555 SHOW(BUTTON5_DOUBLE_CLICKED, "doubleclick-5");
556 SHOW(BUTTON5_TRIPLE_CLICKED, "tripleclick-5");
557 #endif
559 SHOW(BUTTON_CTRL, "ctrl");
560 SHOW(BUTTON_SHIFT, "shift");
561 SHOW(BUTTON_ALT, "alt");
562 SHOW(ALL_MOUSE_EVENTS, "all-events");
563 SHOW(REPORT_MOUSE_POSITION, "position");
565 #undef SHOW
567 if (buf[strlen(buf) - 1] == ' ')
568 buf[strlen(buf) - 2] = '\0';
569 (void) strcat(buf, "}");
570 return (buf);
573 static void
574 show_mouse(WINDOW *win)
576 int y, x;
577 MEVENT event;
578 bool outside;
579 bool show_loc;
581 getmouse(&event);
582 outside = !wenclose(win, event.y, event.x);
584 if (outside) {
585 (void) wstandout(win);
586 waddstr(win, "KEY_MOUSE");
587 (void) wstandend(win);
588 } else {
589 waddstr(win, "KEY_MOUSE");
591 wprintw(win, ", %s", mouse_decode(&event));
593 if (outside)
594 win = stdscr;
596 show_loc = wmouse_trafo(win, &event.y, &event.x, FALSE);
598 if (show_loc) {
599 getyx(win, y, x);
600 wmove(win, event.y, event.x);
601 waddch(win, '*');
602 wmove(win, y, x);
605 if (outside)
606 wnoutrefresh(win);
608 #endif /* NCURSES_MOUSE_VERSION */
610 /****************************************************************************
612 * Character input test
614 ****************************************************************************/
616 #define NUM_GETCH_FLAGS 256
617 typedef bool GetchFlags[NUM_GETCH_FLAGS];
619 static void
620 setup_getch(WINDOW *win, GetchFlags flags)
622 keypad(win, flags['k']); /* should be redundant, but for testing */
623 meta(win, flags['m']); /* force this to a known state */
624 if (flags['e'])
625 echo();
626 else
627 noecho();
630 static void
631 init_getch(WINDOW *win, GetchFlags flags)
633 memset(flags, FALSE, NUM_GETCH_FLAGS);
634 flags[UChar('k')] = (win == stdscr);
635 flags[UChar('m')] = TRUE;
637 setup_getch(win, flags);
640 static void
641 wgetch_help(WINDOW *win, GetchFlags flags)
643 static const char *help[] =
645 "e -- toggle echo mode"
646 ,"g -- triggers a getstr test"
647 ,"k -- toggle keypad/literal mode"
648 ,"m -- toggle meta (7-bit/8-bit) mode"
649 ,"^q -- quit"
650 ,"s -- shell out\n"
651 ,"w -- create a new window"
652 #ifdef SIGTSTP
653 ,"z -- suspend this process"
654 #endif
656 int y, x;
657 unsigned chk = ((SIZEOF(help) + 1) / 2);
658 unsigned n;
660 getyx(win, y, x);
661 move(0, 0);
662 printw("Type any key to see its %s value. Also:\n",
663 flags['k'] ? "keypad" : "literal");
664 for (n = 0; n < SIZEOF(help); ++n) {
665 int row = 1 + (int) (n % chk);
666 int col = (n >= chk) ? COLS / 2 : 0;
667 int flg = ((strstr(help[n], "toggle") != 0)
668 && (flags[UChar(*help[n])] != FALSE));
669 if (flg)
670 (void) standout();
671 MvPrintw(row, col, "%s", help[n]);
672 if (col == 0)
673 clrtoeol();
674 if (flg)
675 (void) standend();
677 wrefresh(stdscr);
678 wmove(win, y, x);
681 static void
682 wgetch_wrap(WINDOW *win, int first_y)
684 int last_y = getmaxy(win) - 1;
685 int y = getcury(win) + 1;
687 if (y >= last_y)
688 y = first_y;
689 wmove(win, y, 0);
690 wclrtoeol(win);
693 #if defined(KEY_RESIZE) && HAVE_WRESIZE
694 typedef struct {
695 WINDOW *text;
696 WINDOW *frame;
697 } WINSTACK;
699 static WINSTACK *winstack = 0;
700 static unsigned len_winstack = 0;
702 static void
703 forget_boxes(void)
705 if (winstack != 0) {
706 free(winstack);
708 winstack = 0;
709 len_winstack = 0;
712 static void
713 remember_boxes(unsigned level, WINDOW *txt_win, WINDOW *box_win)
715 unsigned need = (level + 1) * 2;
717 assert(level < (unsigned) COLS);
719 if (winstack == 0) {
720 len_winstack = 20;
721 winstack = typeMalloc(WINSTACK, len_winstack);
722 } else if (need >= len_winstack) {
723 len_winstack = need;
724 winstack = typeRealloc(WINSTACK, len_winstack, winstack);
726 winstack[level].text = txt_win;
727 winstack[level].frame = box_win;
730 #if USE_SOFTKEYS && (defined(NCURSES_VERSION_PATCH) && NCURSES_VERSION_PATCH < 20071229) && NCURSES_EXT_FUNCS
731 static void
732 slk_repaint(void)
734 /* this chunk is now done in resize_term() */
735 slk_touch();
736 slk_clear();
737 slk_noutrefresh();
740 #else
741 #define slk_repaint() /* nothing */
742 #endif
744 #if defined(NCURSES_VERSION) && defined(KEY_RESIZE) && HAVE_WRESIZE
746 * For wgetch_test(), we create pairs of windows - one for a box, one for text.
747 * Resize both and paint the box in the parent.
749 static void
750 resize_boxes(unsigned level, WINDOW *win)
752 unsigned n;
753 int base = 5;
754 int high = LINES - base;
755 int wide = COLS;
757 touchwin(stdscr);
758 wnoutrefresh(stdscr);
760 slk_repaint();
762 for (n = 0; n < level; ++n) {
763 wresize(winstack[n].frame, high, wide);
764 wresize(winstack[n].text, high - 2, wide - 2);
765 high -= 2;
766 wide -= 2;
767 werase(winstack[n].text);
768 box(winstack[n].frame, 0, 0);
769 wnoutrefresh(winstack[n].frame);
770 wprintw(winstack[n].text,
771 "size %dx%d\n",
772 getmaxy(winstack[n].text),
773 getmaxx(winstack[n].text));
774 wnoutrefresh(winstack[n].text);
775 if (winstack[n].text == win)
776 break;
778 doupdate();
780 #endif /* resize_boxes */
781 #else
782 #define forget_boxes() /* nothing */
783 #define remember_boxes(level,text,frame) /* nothing */
784 #endif
786 static void
787 wgetch_test(unsigned level, WINDOW *win, int delay)
789 char buf[BUFSIZ];
790 int first_y, first_x;
791 int c;
792 int incount = 0;
793 GetchFlags flags;
794 bool blocking = (delay < 0);
796 init_getch(win, flags);
797 wtimeout(win, delay);
798 getyx(win, first_y, first_x);
800 wgetch_help(win, flags);
801 wsetscrreg(win, first_y, getmaxy(win) - 1);
802 scrollok(win, TRUE);
804 for (;;) {
805 while ((c = wGetchar(win)) == ERR) {
806 incount++;
807 if (blocking) {
808 (void) wprintw(win, "%05d: input error", incount);
809 break;
810 } else {
811 (void) wprintw(win, "%05d: input timed out", incount);
813 wgetch_wrap(win, first_y);
815 if (c == ERR && blocking) {
816 wprintw(win, "ERR");
817 wgetch_wrap(win, first_y);
818 } else if (isQuit(c)) {
819 break;
820 } else if (c == 'e') {
821 flags[UChar('e')] = !flags[UChar('e')];
822 setup_getch(win, flags);
823 wgetch_help(win, flags);
824 } else if (c == 'g') {
825 waddstr(win, "getstr test: ");
826 echo();
827 wgetnstr(win, buf, sizeof(buf) - 1);
828 noecho();
829 wprintw(win, "I saw %d characters:\n\t`%s'.", (int) strlen(buf), buf);
830 wclrtoeol(win);
831 wgetch_wrap(win, first_y);
832 } else if (c == 'k') {
833 flags[UChar('k')] = !flags[UChar('k')];
834 setup_getch(win, flags);
835 wgetch_help(win, flags);
836 } else if (c == 'm') {
837 flags[UChar('m')] = !flags[UChar('m')];
838 setup_getch(win, flags);
839 wgetch_help(win, flags);
840 } else if (c == 's') {
841 ShellOut(TRUE);
842 } else if (c == 'w') {
843 int high = getmaxy(win) - 1 - first_y + 1;
844 int wide = getmaxx(win) - first_x;
845 int old_y, old_x;
846 int new_y = first_y + getbegy(win);
847 int new_x = first_x + getbegx(win);
849 getyx(win, old_y, old_x);
850 if (high > 2 && wide > 2) {
851 WINDOW *wb = newwin(high, wide, new_y, new_x);
852 WINDOW *wi = newwin(high - 2, wide - 2, new_y + 1, new_x + 1);
854 box(wb, 0, 0);
855 wrefresh(wb);
856 wmove(wi, 0, 0);
857 remember_boxes(level, wi, wb);
858 wgetch_test(level + 1, wi, delay);
859 delwin(wi);
860 delwin(wb);
862 wgetch_help(win, flags);
863 wmove(win, old_y, old_x);
864 touchwin(win);
865 wrefresh(win);
866 doupdate();
868 #ifdef SIGTSTP
869 } else if (c == 'z') {
870 kill(getpid(), SIGTSTP);
871 #endif
872 } else {
873 wprintw(win, "Key pressed: %04o ", c);
874 #ifdef NCURSES_MOUSE_VERSION
875 if (c == KEY_MOUSE) {
876 show_mouse(win);
877 } else
878 #endif /* NCURSES_MOUSE_VERSION */
879 if (c >= KEY_MIN) {
880 #if defined(NCURSES_VERSION) && defined(KEY_RESIZE) && HAVE_WRESIZE
881 if (c == KEY_RESIZE) {
882 resize_boxes(level, win);
884 #endif
885 (void) waddstr(win, keyname(c));
886 } else if (c >= 0x80) {
887 unsigned c2 = (unsigned) c;
888 #if !(defined(NCURSES_VERSION) || defined(_XOPEN_CURSES))
889 /* at least Solaris SVR4 curses breaks unctrl(128), etc. */
890 c2 &= 0x7f;
891 #endif
892 if (isprint(c))
893 (void) wprintw(win, "%c", UChar(c));
894 else if (c2 != UChar(c))
895 (void) wprintw(win, "M-%s", unctrl(c2));
896 else
897 (void) wprintw(win, "%s", unctrl(c2));
898 waddstr(win, " (high-half character)");
899 } else {
900 if (isprint(c))
901 (void) wprintw(win, "%c (ASCII printable character)", c);
902 else
903 (void) wprintw(win, "%s (ASCII control character)",
904 unctrl(UChar(c)));
906 wgetch_wrap(win, first_y);
910 wtimeout(win, -1);
912 if (!level)
913 init_getch(win, flags);
916 static int
917 begin_getch_test(void)
919 char buf[BUFSIZ];
920 int delay;
922 refresh();
924 #ifdef NCURSES_MOUSE_VERSION
925 mousemask(ALL_MOUSE_EVENTS, (mmask_t *) 0);
926 #endif
928 (void) printw("Delay in 10ths of a second (<CR> for blocking input)? ");
929 echo();
930 getnstr(buf, sizeof(buf) - 1);
931 noecho();
932 nonl();
934 if (isdigit(UChar(buf[0]))) {
935 delay = atoi(buf) * 100;
936 } else {
937 delay = -1;
939 raw();
940 move(5, 0);
941 return delay;
944 static void
945 finish_getch_test(void)
947 #ifdef NCURSES_MOUSE_VERSION
948 mousemask(0, (mmask_t *) 0);
949 #endif
950 erase();
951 noraw();
952 nl();
953 endwin();
956 static void
957 getch_test(void)
959 int delay = begin_getch_test();
961 slk_restore();
962 wgetch_test(0, stdscr, delay);
963 forget_boxes();
964 finish_getch_test();
965 slk_clear();
968 #if USE_WIDEC_SUPPORT
970 * For wget_wch_test(), we create pairs of windows - one for a box, one for text.
971 * Resize both and paint the box in the parent.
973 #if defined(KEY_RESIZE) && HAVE_WRESIZE
974 static void
975 resize_wide_boxes(unsigned level, WINDOW *win)
977 unsigned n;
978 int base = 5;
979 int high = LINES - base;
980 int wide = COLS;
982 touchwin(stdscr);
983 wnoutrefresh(stdscr);
985 slk_repaint();
987 for (n = 0; n < level; ++n) {
988 wresize(winstack[n].frame, high, wide);
989 wresize(winstack[n].text, high - 2, wide - 2);
990 high -= 2;
991 wide -= 2;
992 werase(winstack[n].text);
993 box_set(winstack[n].frame, 0, 0);
994 wnoutrefresh(winstack[n].frame);
995 wprintw(winstack[n].text,
996 "size %dx%d\n",
997 getmaxy(winstack[n].text),
998 getmaxx(winstack[n].text));
999 wnoutrefresh(winstack[n].text);
1000 if (winstack[n].text == win)
1001 break;
1003 doupdate();
1005 #endif /* KEY_RESIZE */
1007 static char *
1008 wcstos(const wchar_t *src)
1010 int need;
1011 char *result = 0;
1012 const wchar_t *tmp = src;
1013 #ifndef state_unused
1014 mbstate_t state;
1015 #endif
1017 reset_wchars(state);
1018 if ((need = (int) count_wchars(tmp, 0, &state)) > 0) {
1019 unsigned have = (unsigned) need;
1020 if ((result = typeCalloc(char, have + 1)) != 0) {
1021 tmp = src;
1022 if (trans_wchars(result, tmp, have, &state) != have) {
1023 free(result);
1024 result = 0;
1028 return result;
1031 static void
1032 wget_wch_test(unsigned level, WINDOW *win, int delay)
1034 wchar_t wchar_buf[BUFSIZ];
1035 wint_t wint_buf[BUFSIZ];
1036 int first_y, first_x;
1037 wint_t c;
1038 int incount = 0;
1039 GetchFlags flags;
1040 bool blocking = (delay < 0);
1041 int code;
1042 char *temp;
1044 init_getch(win, flags);
1045 wtimeout(win, delay);
1046 getyx(win, first_y, first_x);
1048 wgetch_help(win, flags);
1049 wsetscrreg(win, first_y, getmaxy(win) - 1);
1050 scrollok(win, TRUE);
1052 for (;;) {
1053 while ((code = wGet_wchar(win, &c)) == ERR) {
1054 incount++;
1055 if (blocking) {
1056 (void) wprintw(win, "%05d: input error", incount);
1057 break;
1058 } else {
1059 (void) wprintw(win, "%05d: input timed out", incount);
1061 wgetch_wrap(win, first_y);
1063 if (code == ERR && blocking) {
1064 wprintw(win, "ERR");
1065 wgetch_wrap(win, first_y);
1066 } else if (isQuit((int) c)) {
1067 break;
1068 } else if (c == 'e') {
1069 flags[UChar('e')] = !flags[UChar('e')];
1070 setup_getch(win, flags);
1071 wgetch_help(win, flags);
1072 } else if (c == 'g') {
1073 waddstr(win, "getstr test: ");
1074 echo();
1075 code = wgetn_wstr(win, wint_buf, sizeof(wint_buf) - 1);
1076 noecho();
1077 if (code == ERR) {
1078 wprintw(win, "wgetn_wstr returns an error.");
1079 } else {
1080 int n;
1081 for (n = 0; (wchar_buf[n] = (wchar_t) wint_buf[n]) != 0; ++n) {
1084 if ((temp = wcstos(wchar_buf)) != 0) {
1085 wprintw(win, "I saw %d characters:\n\t`%s'.",
1086 (int) wcslen(wchar_buf), temp);
1087 free(temp);
1088 } else {
1089 wprintw(win, "I saw %d characters (cannot convert).",
1090 (int) wcslen(wchar_buf));
1093 wclrtoeol(win);
1094 wgetch_wrap(win, first_y);
1095 } else if (c == 'k') {
1096 flags[UChar('k')] = !flags[UChar('k')];
1097 setup_getch(win, flags);
1098 wgetch_help(win, flags);
1099 } else if (c == 'm') {
1100 flags[UChar('m')] = !flags[UChar('m')];
1101 setup_getch(win, flags);
1102 wgetch_help(win, flags);
1103 } else if (c == 's') {
1104 ShellOut(TRUE);
1105 } else if (c == 'w') {
1106 int high = getmaxy(win) - 1 - first_y + 1;
1107 int wide = getmaxx(win) - first_x;
1108 int old_y, old_x;
1109 int new_y = first_y + getbegy(win);
1110 int new_x = first_x + getbegx(win);
1112 getyx(win, old_y, old_x);
1113 if (high > 2 && wide > 2) {
1114 WINDOW *wb = newwin(high, wide, new_y, new_x);
1115 WINDOW *wi = newwin(high - 2, wide - 2, new_y + 1, new_x + 1);
1117 box_set(wb, 0, 0);
1118 wrefresh(wb);
1119 wmove(wi, 0, 0);
1120 remember_boxes(level, wi, wb);
1121 wget_wch_test(level + 1, wi, delay);
1122 delwin(wi);
1123 delwin(wb);
1125 wgetch_help(win, flags);
1126 wmove(win, old_y, old_x);
1127 touchwin(win);
1128 wrefresh(win);
1130 #ifdef SIGTSTP
1131 } else if (c == 'z') {
1132 kill(getpid(), SIGTSTP);
1133 #endif
1134 } else {
1135 wprintw(win, "Key pressed: %04o ", (int) c);
1136 #ifdef NCURSES_MOUSE_VERSION
1137 if (c == KEY_MOUSE) {
1138 show_mouse(win);
1139 } else
1140 #endif /* NCURSES_MOUSE_VERSION */
1141 if (code == KEY_CODE_YES) {
1142 #if defined(KEY_RESIZE) && HAVE_WRESIZE
1143 if (c == KEY_RESIZE) {
1144 resize_wide_boxes(level, win);
1146 #endif
1147 (void) waddstr(win, keyname((wchar_t) c));
1148 } else {
1149 (void) waddstr(win, key_name((wchar_t) c));
1150 if (c < 256 && iscntrl(c)) {
1151 (void) wprintw(win, " (control character)");
1152 } else {
1153 (void) wprintw(win, " = %#x (printable character)",
1154 (unsigned) c);
1157 wgetch_wrap(win, first_y);
1161 wtimeout(win, -1);
1163 if (!level)
1164 init_getch(win, flags);
1167 static void
1168 get_wch_test(void)
1170 int delay = begin_getch_test();
1172 slk_restore();
1173 wget_wch_test(0, stdscr, delay);
1174 forget_boxes();
1175 finish_getch_test();
1176 slk_clear();
1178 #endif
1180 /****************************************************************************
1182 * Character attributes test
1184 ****************************************************************************/
1186 #if HAVE_SETUPTERM || HAVE_TGETENT
1187 #define get_ncv() TIGETNUM("ncv","NC")
1188 #define get_xmc() TIGETNUM("xmc","sg")
1189 #else
1190 #define get_ncv() -1
1191 #define get_xmc() -1
1192 #endif
1194 #if !HAVE_TERMATTRS
1195 static chtype
1196 my_termattrs(void)
1198 static int first = TRUE;
1199 static chtype result = 0;
1201 if (first) {
1202 #if !HAVE_TIGETSTR
1203 char buffer[4096];
1204 char parsed[4096];
1205 char *area_pointer = parsed;
1207 tgetent(buffer, getenv("TERM"));
1208 #endif
1210 if (TIGETSTR("smso", "so"))
1211 result |= A_STANDOUT;
1212 if (TIGETSTR("smul", "us"))
1213 result |= A_UNDERLINE;
1214 if (TIGETSTR("rev", "mr"))
1215 result |= A_REVERSE;
1216 if (TIGETSTR("blink", "mb"))
1217 result |= A_BLINK;
1218 if (TIGETSTR("dim", "mh"))
1219 result |= A_DIM;
1220 if (TIGETSTR("bold", "md"))
1221 result |= A_BOLD;
1222 if (TIGETSTR("smacs", "ac"))
1223 result |= A_ALTCHARSET;
1225 first = FALSE;
1227 return result;
1229 #define termattrs() my_termattrs()
1230 #endif
1232 #define MAX_ATTRSTRING 31
1233 #define LEN_ATTRSTRING 26
1235 static char attr_test_string[MAX_ATTRSTRING + 1];
1237 static void
1238 attr_legend(WINDOW *helpwin)
1240 int row = 1;
1241 int col = 1;
1243 MvWPrintw(helpwin, row++, col,
1244 "ESC to exit.");
1245 MvWPrintw(helpwin, row++, col,
1246 "^L repaints.");
1247 ++row;
1248 MvWPrintw(helpwin, row++, col,
1249 "Modify the test strings:");
1250 MvWPrintw(helpwin, row++, col,
1251 " A digit sets gaps on each side of displayed attributes");
1252 MvWPrintw(helpwin, row++, col,
1253 " </> shifts the text left/right. ");
1254 ++row;
1255 MvWPrintw(helpwin, row++, col,
1256 "Toggles:");
1257 if (use_colors) {
1258 MvWPrintw(helpwin, row++, col,
1259 " f/F/b/F toggle foreground/background background color");
1260 MvWPrintw(helpwin, row++, col,
1261 " t/T toggle text/background color attribute");
1263 MvWPrintw(helpwin, row++, col,
1264 " a/A toggle ACS (alternate character set) mapping");
1265 MvWPrintw(helpwin, row, col,
1266 " v/V toggle video attribute to combine with each line");
1269 static void
1270 show_color_attr(int fg, int bg, int tx)
1272 if (use_colors) {
1273 printw(" Colors (fg %d, bg %d", fg, bg);
1274 if (tx >= 0)
1275 printw(", text %d", tx);
1276 printw("),");
1280 static bool
1281 cycle_color_attr(int ch, short *fg, short *bg, short *tx)
1283 bool error = FALSE;
1285 if (use_colors) {
1286 switch (ch) {
1287 case 'f':
1288 *fg = (short) (*fg + 1);
1289 break;
1290 case 'F':
1291 *fg = (short) (*fg - 1);
1292 break;
1293 case 'b':
1294 *bg = (short) (*bg + 1);
1295 break;
1296 case 'B':
1297 *bg = (short) (*bg - 1);
1298 break;
1299 case 't':
1300 *tx = (short) (*tx + 1);
1301 break;
1302 case 'T':
1303 *tx = (short) (*tx - 1);
1304 break;
1305 default:
1306 beep();
1307 error = TRUE;
1308 break;
1310 if (*fg >= COLORS)
1311 *fg = (short) min_colors;
1312 if (*fg < min_colors)
1313 *fg = (short) (COLORS - 1);
1314 if (*bg >= COLORS)
1315 *bg = (short) min_colors;
1316 if (*bg < min_colors)
1317 *bg = (short) (COLORS - 1);
1318 if (*tx >= COLORS)
1319 *tx = -1;
1320 if (*tx < -1)
1321 *tx = (short) (COLORS - 1);
1322 } else {
1323 beep();
1324 error = TRUE;
1326 return error;
1329 static void
1330 adjust_attr_string(int adjust)
1332 int first = ((int) UChar(attr_test_string[0])) + adjust;
1333 int last = first + LEN_ATTRSTRING;
1335 if (first >= ' ' && last <= '~') { /* 32..126 */
1336 int j, k;
1337 for (j = 0, k = first; j < MAX_ATTRSTRING && k <= last; ++j, ++k) {
1338 attr_test_string[j] = (char) k;
1339 if (((k + 1 - first) % 5) == 0) {
1340 if (++j >= MAX_ATTRSTRING)
1341 break;
1342 attr_test_string[j] = ' ';
1345 while (j < MAX_ATTRSTRING)
1346 attr_test_string[j++] = ' ';
1347 attr_test_string[j] = '\0';
1348 } else {
1349 beep();
1353 static void
1354 init_attr_string(void)
1356 attr_test_string[0] = 'a';
1357 adjust_attr_string(0);
1360 static int
1361 show_attr(int row, int skip, bool arrow, chtype attr, const char *name)
1363 int ncv = get_ncv();
1364 chtype test = attr & (chtype) (~A_ALTCHARSET);
1366 if (arrow)
1367 MvPrintw(row, 5, "-->");
1368 MvPrintw(row, 8, "%s mode:", name);
1369 MvPrintw(row, 24, "|");
1370 if (skip)
1371 printw("%*s", skip, " ");
1373 * Just for testing, write text using the alternate character set one
1374 * character at a time (to pass its rendition directly), and use the
1375 * string operation for the other attributes.
1377 if (attr & A_ALTCHARSET) {
1378 const char *s;
1379 chtype ch;
1381 for (s = attr_test_string; *s != '\0'; ++s) {
1382 ch = UChar(*s);
1383 addch(ch | attr);
1385 } else {
1386 (void) attrset(attr);
1387 addstr(attr_test_string);
1388 attroff(attr);
1390 if (skip)
1391 printw("%*s", skip, " ");
1392 printw("|");
1393 if (test != A_NORMAL) {
1394 if (!(termattrs() & test)) {
1395 printw(" (N/A)");
1396 } else {
1397 if (ncv > 0 && (getbkgd(stdscr) & A_COLOR)) {
1398 static const chtype table[] =
1400 A_STANDOUT,
1401 A_UNDERLINE,
1402 A_REVERSE,
1403 A_BLINK,
1404 A_DIM,
1405 A_BOLD,
1406 #ifdef A_INVIS
1407 A_INVIS,
1408 #endif
1409 A_PROTECT,
1410 A_ALTCHARSET
1412 unsigned n;
1413 bool found = FALSE;
1414 for (n = 0; n < SIZEOF(table); n++) {
1415 if ((table[n] & attr) != 0
1416 && ((1 << n) & ncv) != 0) {
1417 found = TRUE;
1418 break;
1421 if (found)
1422 printw(" (NCV)");
1424 if ((termattrs() & test) != test)
1425 printw(" (Part)");
1428 return row + 2;
1430 /* *INDENT-OFF* */
1431 static const struct {
1432 chtype attr;
1433 NCURSES_CONST char * name;
1434 } attrs_to_test[] = {
1435 { A_STANDOUT, "STANDOUT" },
1436 { A_REVERSE, "REVERSE" },
1437 { A_BOLD, "BOLD" },
1438 { A_UNDERLINE, "UNDERLINE" },
1439 { A_DIM, "DIM" },
1440 { A_BLINK, "BLINK" },
1441 { A_PROTECT, "PROTECT" },
1442 #ifdef A_INVIS
1443 { A_INVIS, "INVISIBLE" },
1444 #endif
1445 { A_NORMAL, "NORMAL" },
1447 /* *INDENT-ON* */
1449 static bool
1450 attr_getc(int *skip, short *fg, short *bg, short *tx, int *ac, unsigned *kc)
1452 bool result = TRUE;
1453 bool error = FALSE;
1454 WINDOW *helpwin;
1456 do {
1457 int ch = Getchar();
1459 error = FALSE;
1460 if (ch < 256 && isdigit(ch)) {
1461 *skip = (ch - '0');
1462 } else {
1463 switch (ch) {
1464 case CTRL('L'):
1465 Repaint();
1466 break;
1467 case '?':
1468 if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) {
1469 box(helpwin, 0, 0);
1470 attr_legend(helpwin);
1471 wGetchar(helpwin);
1472 delwin(helpwin);
1474 break;
1475 case 'a':
1476 *ac = 0;
1477 break;
1478 case 'A':
1479 *ac = A_ALTCHARSET;
1480 break;
1481 case 'v':
1482 if (*kc == 0)
1483 *kc = SIZEOF(attrs_to_test) - 1;
1484 else
1485 *kc -= 1;
1486 break;
1487 case 'V':
1488 *kc += 1;
1489 if (*kc >= SIZEOF(attrs_to_test))
1490 *kc = 0;
1491 break;
1492 case '<':
1493 adjust_attr_string(-1);
1494 break;
1495 case '>':
1496 adjust_attr_string(1);
1497 break;
1498 case case_QUIT:
1499 result = FALSE;
1500 break;
1501 default:
1502 error = cycle_color_attr(ch, fg, bg, tx);
1503 break;
1506 } while (error);
1507 return result;
1510 static void
1511 attr_test(void)
1512 /* test text attributes */
1514 int n;
1515 int skip = get_xmc();
1516 short fg = COLOR_BLACK; /* color pair 0 is special */
1517 short bg = COLOR_BLACK;
1518 short tx = -1;
1519 int ac = 0;
1520 unsigned j, k;
1522 if (skip < 0)
1523 skip = 0;
1525 n = skip; /* make it easy */
1526 k = SIZEOF(attrs_to_test) - 1;
1527 init_attr_string();
1529 do {
1530 int row = 2;
1531 chtype normal = A_NORMAL | BLANK;
1532 chtype extras = (chtype) ac;
1534 if (use_colors) {
1535 short pair = (short) (fg != COLOR_BLACK || bg != COLOR_BLACK);
1536 if (pair != 0) {
1537 pair = 1;
1538 if (init_pair(pair, fg, bg) == ERR) {
1539 beep();
1540 } else {
1541 normal |= (chtype) COLOR_PAIR(pair);
1544 if (tx >= 0) {
1545 pair = 2;
1546 if (init_pair(pair, tx, bg) == ERR) {
1547 beep();
1548 } else {
1549 extras |= (chtype) COLOR_PAIR(pair);
1553 bkgd(normal);
1554 bkgdset(normal);
1555 erase();
1557 box(stdscr, 0, 0);
1558 MvAddStr(0, 20, "Character attribute test display");
1560 for (j = 0; j < SIZEOF(attrs_to_test); ++j) {
1561 bool arrow = (j == k);
1562 row = show_attr(row, n, arrow,
1563 extras |
1564 attrs_to_test[j].attr |
1565 attrs_to_test[k].attr,
1566 attrs_to_test[j].name);
1569 MvPrintw(row, 8,
1570 "This terminal does %shave the magic-cookie glitch",
1571 get_xmc() > -1 ? "" : "not ");
1572 MvPrintw(row + 1, 8, "Enter '?' for help.");
1573 show_color_attr(fg, bg, tx);
1574 printw(" ACS (%d)", ac != 0);
1576 refresh();
1577 } while (attr_getc(&n, &fg, &bg, &tx, &ac, &k));
1579 bkgdset(A_NORMAL | BLANK);
1580 erase();
1581 endwin();
1584 #if USE_WIDEC_SUPPORT
1585 static wchar_t wide_attr_test_string[MAX_ATTRSTRING + 1];
1587 static void
1588 wide_adjust_attr_string(int adjust)
1590 int first = ((int) UChar(wide_attr_test_string[0])) + adjust;
1591 int last = first + LEN_ATTRSTRING;
1593 if (first >= ' ' && last <= '~') { /* 32..126 */
1594 int j, k;
1595 for (j = 0, k = first; j < MAX_ATTRSTRING && k <= last; ++j, ++k) {
1596 wide_attr_test_string[j] = k;
1597 if (((k + 1 - first) % 5) == 0) {
1598 if (++j >= MAX_ATTRSTRING)
1599 break;
1600 wide_attr_test_string[j] = ' ';
1603 while (j < MAX_ATTRSTRING)
1604 wide_attr_test_string[j++] = ' ';
1605 wide_attr_test_string[j] = '\0';
1606 } else {
1607 beep();
1611 static void
1612 wide_init_attr_string(void)
1614 wide_attr_test_string[0] = 'a';
1615 wide_adjust_attr_string(0);
1618 static void
1619 set_wide_background(short pair)
1621 cchar_t normal;
1622 wchar_t blank[2];
1624 blank[0] = ' ';
1625 blank[1] = 0;
1626 setcchar(&normal, blank, A_NORMAL, pair, 0);
1627 bkgrnd(&normal);
1628 bkgrndset(&normal);
1631 static attr_t
1632 get_wide_background(void)
1634 attr_t result = A_NORMAL;
1635 attr_t attr;
1636 cchar_t ch;
1637 short pair;
1638 wchar_t wch[10];
1640 if (getbkgrnd(&ch) != ERR) {
1641 if (getcchar(&ch, wch, &attr, &pair, 0) != ERR) {
1642 result = attr;
1645 return result;
1648 static int
1649 wide_show_attr(int row, int skip, bool arrow, chtype attr, short pair, const char *name)
1651 int ncv = get_ncv();
1652 chtype test = attr & ~WA_ALTCHARSET;
1654 if (arrow)
1655 MvPrintw(row, 5, "-->");
1656 MvPrintw(row, 8, "%s mode:", name);
1657 MvPrintw(row, 24, "|");
1658 if (skip)
1659 printw("%*s", skip, " ");
1662 * Just for testing, write text using the alternate character set one
1663 * character at a time (to pass its rendition directly), and use the
1664 * string operation for the other attributes.
1666 if (attr & WA_ALTCHARSET) {
1667 const wchar_t *s;
1668 cchar_t ch;
1670 for (s = wide_attr_test_string; *s != L'\0'; ++s) {
1671 wchar_t fill[2];
1672 fill[0] = *s;
1673 fill[1] = L'\0';
1674 setcchar(&ch, fill, attr, pair, 0);
1675 add_wch(&ch);
1677 } else {
1678 attr_t old_attr;
1679 short old_pair;
1681 (void) attr_get(&old_attr, &old_pair, 0);
1682 (void) attr_set(attr, pair, 0);
1683 addwstr(wide_attr_test_string);
1684 (void) attr_set(old_attr, old_pair, 0);
1686 if (skip)
1687 printw("%*s", skip, " ");
1688 printw("|");
1689 if (test != A_NORMAL) {
1690 if (!(term_attrs() & test)) {
1691 printw(" (N/A)");
1692 } else {
1693 if (ncv > 0 && (get_wide_background() & A_COLOR)) {
1694 static const attr_t table[] =
1696 WA_STANDOUT,
1697 WA_UNDERLINE,
1698 WA_REVERSE,
1699 WA_BLINK,
1700 WA_DIM,
1701 WA_BOLD,
1702 WA_INVIS,
1703 WA_PROTECT,
1704 WA_ALTCHARSET
1706 unsigned n;
1707 bool found = FALSE;
1708 for (n = 0; n < SIZEOF(table); n++) {
1709 if ((table[n] & attr) != 0
1710 && ((1 << n) & ncv) != 0) {
1711 found = TRUE;
1712 break;
1715 if (found)
1716 printw(" (NCV)");
1718 if ((term_attrs() & test) != test)
1719 printw(" (Part)");
1722 return row + 2;
1725 static bool
1726 wide_attr_getc(int *skip, short *fg, short *bg, short *tx, int *ac, unsigned *kc)
1728 bool result = TRUE;
1729 bool error = FALSE;
1730 WINDOW *helpwin;
1732 do {
1733 int ch = Getchar();
1735 error = FALSE;
1736 if (ch < 256 && isdigit(ch)) {
1737 *skip = (ch - '0');
1738 } else {
1739 switch (ch) {
1740 case CTRL('L'):
1741 Repaint();
1742 break;
1743 case '?':
1744 if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) {
1745 box_set(helpwin, 0, 0);
1746 attr_legend(helpwin);
1747 wGetchar(helpwin);
1748 delwin(helpwin);
1750 break;
1751 case 'a':
1752 *ac = 0;
1753 break;
1754 case 'A':
1755 *ac = A_ALTCHARSET;
1756 break;
1757 case 'v':
1758 if (*kc == 0)
1759 *kc = SIZEOF(attrs_to_test) - 1;
1760 else
1761 *kc -= 1;
1762 break;
1763 case 'V':
1764 *kc += 1;
1765 if (*kc >= SIZEOF(attrs_to_test))
1766 *kc = 0;
1767 break;
1768 case '<':
1769 wide_adjust_attr_string(-1);
1770 break;
1771 case '>':
1772 wide_adjust_attr_string(1);
1773 break;
1774 case case_QUIT:
1775 result = FALSE;
1776 break;
1777 default:
1778 error = cycle_color_attr(ch, fg, bg, tx);
1779 break;
1782 } while (error);
1783 return result;
1786 static void
1787 wide_attr_test(void)
1788 /* test text attributes using wide-character calls */
1790 int n;
1791 int skip = get_xmc();
1792 short fg = COLOR_BLACK; /* color pair 0 is special */
1793 short bg = COLOR_BLACK;
1794 short tx = -1;
1795 int ac = 0;
1796 unsigned j, k;
1798 if (skip < 0)
1799 skip = 0;
1801 n = skip; /* make it easy */
1802 k = SIZEOF(attrs_to_test) - 1;
1803 wide_init_attr_string();
1805 do {
1806 int row = 2;
1807 short pair = 0;
1808 short extras = 0;
1810 if (use_colors) {
1811 pair = (short) (fg != COLOR_BLACK || bg != COLOR_BLACK);
1812 if (pair != 0) {
1813 pair = 1;
1814 if (init_pair(pair, fg, bg) == ERR) {
1815 beep();
1818 extras = pair;
1819 if (tx >= 0) {
1820 extras = 2;
1821 if (init_pair(extras, tx, bg) == ERR) {
1822 beep();
1826 set_wide_background(pair);
1827 erase();
1829 box_set(stdscr, 0, 0);
1830 MvAddStr(0, 20, "Character attribute test display");
1832 for (j = 0; j < SIZEOF(attrs_to_test); ++j) {
1833 row = wide_show_attr(row, n, j == k,
1834 ((attr_t) ac |
1835 attrs_to_test[j].attr |
1836 attrs_to_test[k].attr),
1837 extras,
1838 attrs_to_test[j].name);
1841 MvPrintw(row, 8,
1842 "This terminal does %shave the magic-cookie glitch",
1843 get_xmc() > -1 ? "" : "not ");
1844 MvPrintw(row + 1, 8, "Enter '?' for help.");
1845 show_color_attr(fg, bg, tx);
1846 printw(" ACS (%d)", ac != 0);
1848 refresh();
1849 } while (wide_attr_getc(&n, &fg, &bg, &tx, &ac, &k));
1851 set_wide_background(0);
1852 erase();
1853 endwin();
1855 #endif
1857 /****************************************************************************
1859 * Color support tests
1861 ****************************************************************************/
1863 static NCURSES_CONST char *the_color_names[] =
1865 "black",
1866 "red",
1867 "green",
1868 "yellow",
1869 "blue",
1870 "magenta",
1871 "cyan",
1872 "white",
1873 "BLACK",
1874 "RED",
1875 "GREEN",
1876 "YELLOW",
1877 "BLUE",
1878 "MAGENTA",
1879 "CYAN",
1880 "WHITE"
1883 static void
1884 show_color_name(int y, int x, int color, bool wide)
1886 if (move(y, x) != ERR) {
1887 char temp[80];
1888 int width = 8;
1890 if (wide) {
1891 sprintf(temp, "%02d", color);
1892 width = 4;
1893 } else if (color >= 8) {
1894 sprintf(temp, "[%02d]", color);
1895 } else if (color < 0) {
1896 strcpy(temp, "default");
1897 } else {
1898 strcpy(temp, the_color_names[color]);
1900 printw("%-*.*s", width, width, temp);
1904 static void
1905 color_legend(WINDOW *helpwin, bool wide)
1907 int row = 1;
1908 int col = 1;
1910 MvWPrintw(helpwin, row++, col,
1911 "ESC to exit.");
1912 ++row;
1913 MvWPrintw(helpwin, row++, col,
1914 "Use up/down arrow to scroll through the display if it is");
1915 MvWPrintw(helpwin, row++, col,
1916 "longer than one screen. Control/N and Control/P can be used");
1917 MvWPrintw(helpwin, row++, col,
1918 "in place of up/down arrow. Use pageup/pagedown to scroll a");
1919 MvWPrintw(helpwin, row++, col,
1920 "full screen; control/B and control/F can be used here.");
1921 ++row;
1922 MvWPrintw(helpwin, row++, col,
1923 "Toggles:");
1924 MvWPrintw(helpwin, row++, col,
1925 " a/A toggle altcharset off/on");
1926 MvWPrintw(helpwin, row++, col,
1927 " b/B toggle bold off/on");
1928 MvWPrintw(helpwin, row++, col,
1929 " n/N toggle text/number on/off");
1930 MvWPrintw(helpwin, row++, col,
1931 " r/R toggle reverse on/off");
1932 MvWPrintw(helpwin, row++, col,
1933 " w/W toggle width between 8/16 colors");
1934 #if USE_WIDEC_SUPPORT
1935 if (wide) {
1936 MvWPrintw(helpwin, row++, col,
1937 "Wide characters:");
1938 MvWPrintw(helpwin, row, col,
1939 " x/X toggle text between ASCII and wide-character");
1941 #else
1942 (void) wide;
1943 #endif
1946 #define set_color_test(name, value) if (name != value) { name = value; base_row = 0; }
1948 /* generate a color test pattern */
1949 static void
1950 color_test(void)
1952 short i;
1953 int top = 0, width;
1954 int base_row = 0;
1955 int grid_top = top + 3;
1956 int page_size = (LINES - grid_top);
1957 int pairs_max = PAIR_NUMBER(A_COLOR) + 1;
1958 int row_limit;
1959 int per_row;
1960 char numbered[80];
1961 const char *hello;
1962 bool done = FALSE;
1963 bool opt_acsc = FALSE;
1964 bool opt_bold = FALSE;
1965 bool opt_revs = FALSE;
1966 bool opt_nums = FALSE;
1967 bool opt_wide = FALSE;
1968 WINDOW *helpwin;
1970 if (COLORS * COLORS == COLOR_PAIRS) {
1971 int limit = (COLORS - min_colors) * (COLORS - min_colors);
1972 if (pairs_max > limit)
1973 pairs_max = limit;
1974 } else {
1975 if (pairs_max > COLOR_PAIRS)
1976 pairs_max = COLOR_PAIRS;
1979 while (!done) {
1980 int shown = 0;
1982 /* this assumes an 80-column line */
1983 if (opt_wide) {
1984 width = 4;
1985 hello = "Test";
1986 per_row = (COLORS > 8) ? 16 : 8;
1987 } else {
1988 width = 8;
1989 hello = "Hello";
1990 per_row = 8;
1992 per_row -= min_colors;
1994 row_limit = (pairs_max + per_row - 1) / per_row;
1996 move(0, 0);
1997 (void) printw("There are %d color pairs and %d colors%s\n",
1998 pairs_max, COLORS,
1999 min_colors ? " besides 'default'" : "");
2001 clrtobot();
2002 MvPrintw(top + 1, 0,
2003 "%dx%d matrix of foreground/background colors, bold *%s*\n",
2004 row_limit,
2005 per_row,
2006 opt_bold ? "on" : "off");
2008 /* show color names/numbers across the top */
2009 for (i = 0; i < per_row; i++)
2010 show_color_name(top + 2, (i + 1) * width, i + min_colors, opt_wide);
2012 /* show a grid of colors, with color names/ numbers on the left */
2013 for (i = (short) (base_row * per_row); i < pairs_max; i++) {
2014 int row = grid_top + (i / per_row) - base_row;
2015 int col = (i % per_row + 1) * width;
2016 short pair = i;
2018 #define InxToFG(i) (short) ((i % (COLORS - min_colors)) + min_colors)
2019 #define InxToBG(i) (short) ((i / (COLORS - min_colors)) + min_colors)
2020 if (row >= 0 && move(row, col) != ERR) {
2021 short fg = InxToFG(i);
2022 short bg = InxToBG(i);
2024 init_pair(pair, fg, bg);
2025 attron((attr_t) COLOR_PAIR(pair));
2026 if (opt_acsc)
2027 attron((attr_t) A_ALTCHARSET);
2028 if (opt_bold)
2029 attron((attr_t) A_BOLD);
2030 if (opt_revs)
2031 attron((attr_t) A_REVERSE);
2033 if (opt_nums) {
2034 sprintf(numbered, "{%02X}", i);
2035 hello = numbered;
2037 printw("%-*.*s", width, width, hello);
2038 (void) attrset(A_NORMAL);
2040 if ((i % per_row) == 0 && InxToFG(i) == min_colors) {
2041 show_color_name(row, 0, InxToBG(i), opt_wide);
2043 ++shown;
2044 } else if (shown) {
2045 break;
2049 switch (wGetchar(stdscr)) {
2050 case 'a':
2051 opt_acsc = FALSE;
2052 break;
2053 case 'A':
2054 opt_acsc = TRUE;
2055 break;
2056 case 'b':
2057 opt_bold = FALSE;
2058 break;
2059 case 'B':
2060 opt_bold = TRUE;
2061 break;
2062 case 'n':
2063 opt_nums = FALSE;
2064 break;
2065 case 'N':
2066 opt_nums = TRUE;
2067 break;
2068 case 'r':
2069 opt_revs = FALSE;
2070 break;
2071 case 'R':
2072 opt_revs = TRUE;
2073 break;
2074 case case_QUIT:
2075 done = TRUE;
2076 continue;
2077 case 'w':
2078 set_color_test(opt_wide, FALSE);
2079 break;
2080 case 'W':
2081 set_color_test(opt_wide, TRUE);
2082 break;
2083 case CTRL('p'):
2084 case KEY_UP:
2085 if (base_row <= 0) {
2086 beep();
2087 } else {
2088 base_row -= 1;
2090 break;
2091 case CTRL('n'):
2092 case KEY_DOWN:
2093 if (base_row + page_size >= row_limit) {
2094 beep();
2095 } else {
2096 base_row += 1;
2098 break;
2099 case CTRL('b'):
2100 case KEY_PREVIOUS:
2101 case KEY_PPAGE:
2102 if (base_row <= 0) {
2103 beep();
2104 } else {
2105 base_row -= (page_size - 1);
2106 if (base_row < 0)
2107 base_row = 0;
2109 break;
2110 case CTRL('f'):
2111 case KEY_NEXT:
2112 case KEY_NPAGE:
2113 if (base_row + page_size >= row_limit) {
2114 beep();
2115 } else {
2116 base_row += page_size - 1;
2117 if (base_row + page_size >= row_limit) {
2118 base_row = row_limit - page_size - 1;
2121 break;
2122 case '?':
2123 if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) {
2124 box(helpwin, 0, 0);
2125 color_legend(helpwin, FALSE);
2126 wGetchar(helpwin);
2127 delwin(helpwin);
2129 break;
2130 default:
2131 beep();
2132 continue;
2136 erase();
2137 endwin();
2140 #if USE_WIDEC_SUPPORT
2141 /* generate a color test pattern */
2142 static void
2143 wide_color_test(void)
2145 int i;
2146 int top = 0, width;
2147 int base_row = 0;
2148 int grid_top = top + 3;
2149 int page_size = (LINES - grid_top);
2150 int pairs_max = (unsigned short) (-1);
2151 int row_limit;
2152 int per_row;
2153 char numbered[80];
2154 const char *hello;
2155 bool done = FALSE;
2156 bool opt_acsc = FALSE;
2157 bool opt_bold = FALSE;
2158 bool opt_revs = FALSE;
2159 bool opt_wide = FALSE;
2160 bool opt_nums = FALSE;
2161 bool opt_xchr = FALSE;
2162 wchar_t buffer[10];
2163 WINDOW *helpwin;
2165 if (COLORS * COLORS == COLOR_PAIRS) {
2166 int limit = (COLORS - min_colors) * (COLORS - min_colors);
2167 if (pairs_max > limit)
2168 pairs_max = limit;
2169 } else {
2170 if (pairs_max > COLOR_PAIRS)
2171 pairs_max = COLOR_PAIRS;
2174 while (!done) {
2175 int shown = 0;
2177 /* this assumes an 80-column line */
2178 if (opt_wide) {
2179 width = 4;
2180 hello = "Test";
2181 per_row = (COLORS > 8) ? 16 : 8;
2182 } else {
2183 width = 8;
2184 hello = "Hello";
2185 per_row = 8;
2187 per_row -= min_colors;
2189 if (opt_xchr) {
2190 make_fullwidth_text(buffer, hello);
2191 width *= 2;
2192 per_row /= 2;
2193 } else {
2194 make_narrow_text(buffer, hello);
2197 row_limit = (pairs_max + per_row - 1) / per_row;
2199 move(0, 0);
2200 (void) printw("There are %d color pairs and %d colors%s\n",
2201 pairs_max, COLORS,
2202 min_colors ? " besides 'default'" : "");
2204 clrtobot();
2205 MvPrintw(top + 1, 0,
2206 "%dx%d matrix of foreground/background colors, bold *%s*\n",
2207 row_limit,
2208 per_row,
2209 opt_bold ? "on" : "off");
2211 /* show color names/numbers across the top */
2212 for (i = 0; i < per_row; i++)
2213 show_color_name(top + 2, (i + 1) * width, i + min_colors, opt_wide);
2215 /* show a grid of colors, with color names/ numbers on the left */
2216 for (i = (base_row * per_row); i < pairs_max; i++) {
2217 int row = grid_top + (i / per_row) - base_row;
2218 int col = (i % per_row + 1) * width;
2219 short pair = (short) i;
2221 if (row >= 0 && move(row, col) != ERR) {
2222 init_pair(pair, InxToFG(i), InxToBG(i));
2223 color_set(pair, NULL);
2224 if (opt_acsc)
2225 attr_on((attr_t) A_ALTCHARSET, NULL);
2226 if (opt_bold)
2227 attr_on((attr_t) A_BOLD, NULL);
2228 if (opt_revs)
2229 attr_on((attr_t) A_REVERSE, NULL);
2231 if (opt_nums) {
2232 sprintf(numbered, "{%02X}", i);
2233 if (opt_xchr) {
2234 make_fullwidth_text(buffer, numbered);
2235 } else {
2236 make_narrow_text(buffer, numbered);
2239 addnwstr(buffer, width);
2240 (void) attr_set(A_NORMAL, 0, NULL);
2242 if ((i % per_row) == 0 && InxToFG(i) == min_colors) {
2243 show_color_name(row, 0, InxToBG(i), opt_wide);
2245 ++shown;
2246 } else if (shown) {
2247 break;
2251 switch (wGetchar(stdscr)) {
2252 case 'a':
2253 opt_acsc = FALSE;
2254 break;
2255 case 'A':
2256 opt_acsc = TRUE;
2257 break;
2258 case 'b':
2259 opt_bold = FALSE;
2260 break;
2261 case 'B':
2262 opt_bold = TRUE;
2263 break;
2264 case 'n':
2265 opt_nums = FALSE;
2266 break;
2267 case 'N':
2268 opt_nums = TRUE;
2269 break;
2270 case 'r':
2271 opt_revs = FALSE;
2272 break;
2273 case 'R':
2274 opt_revs = TRUE;
2275 break;
2276 case case_QUIT:
2277 done = TRUE;
2278 continue;
2279 case 'w':
2280 set_color_test(opt_wide, FALSE);
2281 break;
2282 case 'W':
2283 set_color_test(opt_wide, TRUE);
2284 break;
2285 case 'x':
2286 opt_xchr = FALSE;
2287 break;
2288 case 'X':
2289 opt_xchr = TRUE;
2290 break;
2291 case CTRL('p'):
2292 case KEY_UP:
2293 if (base_row <= 0) {
2294 beep();
2295 } else {
2296 base_row -= 1;
2298 break;
2299 case CTRL('n'):
2300 case KEY_DOWN:
2301 if (base_row + page_size >= row_limit) {
2302 beep();
2303 } else {
2304 base_row += 1;
2306 break;
2307 case CTRL('b'):
2308 case KEY_PREVIOUS:
2309 case KEY_PPAGE:
2310 if (base_row <= 0) {
2311 beep();
2312 } else {
2313 base_row -= (page_size - 1);
2314 if (base_row < 0)
2315 base_row = 0;
2317 break;
2318 case CTRL('f'):
2319 case KEY_NEXT:
2320 case KEY_NPAGE:
2321 if (base_row + page_size >= row_limit) {
2322 beep();
2323 } else {
2324 base_row += page_size - 1;
2325 if (base_row + page_size >= row_limit) {
2326 base_row = row_limit - page_size - 1;
2329 break;
2330 case '?':
2331 if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) {
2332 box(helpwin, 0, 0);
2333 color_legend(helpwin, TRUE);
2334 wGetchar(helpwin);
2335 delwin(helpwin);
2337 break;
2338 default:
2339 beep();
2340 continue;
2344 erase();
2345 endwin();
2347 #endif /* USE_WIDEC_SUPPORT */
2349 static void
2350 change_color(short current, int field, int value, int usebase)
2352 short red, green, blue;
2354 color_content(current, &red, &green, &blue);
2356 switch (field) {
2357 case 0:
2358 red = (short) (usebase ? (red + value) : value);
2359 break;
2360 case 1:
2361 green = (short) (usebase ? (green + value) : value);
2362 break;
2363 case 2:
2364 blue = (short) (usebase ? (blue + value) : value);
2365 break;
2368 if (init_color(current, red, green, blue) == ERR)
2369 beep();
2372 static void
2373 init_all_colors(void)
2375 short c;
2377 for (c = 0; c < COLORS; ++c)
2378 init_color(c,
2379 all_colors[c].red,
2380 all_colors[c].green,
2381 all_colors[c].blue);
2384 #define scaled_rgb(n) ((255 * (n)) / 1000)
2386 static void
2387 color_edit(void)
2388 /* display the color test pattern, without trying to edit colors */
2390 int i;
2391 int current = 0;
2392 int this_c = 0, value = 0, field = 0;
2393 int last_c;
2394 int top_color = 0;
2395 int page_size = (LINES - 6);
2397 init_all_colors();
2398 refresh();
2400 for (i = 0; i < max_colors; i++)
2401 init_pair((short) i, (short) COLOR_WHITE, (short) i);
2403 MvPrintw(LINES - 2, 0, "Number: %d", value);
2405 do {
2406 short red, green, blue;
2408 attron(A_BOLD);
2409 MvAddStr(0, 20, "Color RGB Value Editing");
2410 attroff(A_BOLD);
2412 for (i = (short) top_color;
2413 (i - top_color < page_size)
2414 && (i < max_colors); i++) {
2415 char numeric[80];
2417 sprintf(numeric, "[%d]", i);
2418 MvPrintw(2 + i - top_color, 0, "%c %-8s:",
2419 (i == current ? '>' : ' '),
2420 (i < (int) SIZEOF(the_color_names)
2421 ? the_color_names[i] : numeric));
2422 (void) attrset((attr_t) COLOR_PAIR(i));
2423 addstr(" ");
2424 (void) attrset(A_NORMAL);
2426 color_content((short) i, &red, &green, &blue);
2427 addstr(" R = ");
2428 if (current == i && field == 0)
2429 attron(A_STANDOUT);
2430 printw("%04d", red);
2431 if (current == i && field == 0)
2432 (void) attrset(A_NORMAL);
2433 addstr(", G = ");
2434 if (current == i && field == 1)
2435 attron(A_STANDOUT);
2436 printw("%04d", green);
2437 if (current == i && field == 1)
2438 (void) attrset(A_NORMAL);
2439 addstr(", B = ");
2440 if (current == i && field == 2)
2441 attron(A_STANDOUT);
2442 printw("%04d", blue);
2443 if (current == i && field == 2)
2444 (void) attrset(A_NORMAL);
2445 (void) attrset(A_NORMAL);
2446 printw(" ( %3d %3d %3d )",
2447 scaled_rgb(red),
2448 scaled_rgb(green),
2449 scaled_rgb(blue));
2452 MvAddStr(LINES - 3, 0,
2453 "Use up/down to select a color, left/right to change fields.");
2454 MvAddStr(LINES - 2, 0,
2455 "Modify field by typing nnn=, nnn-, or nnn+. ? for help.");
2457 move(2 + current - top_color, 0);
2459 last_c = this_c;
2460 this_c = Getchar();
2461 if (this_c < 256 && isdigit(this_c) && !isdigit(last_c))
2462 value = 0;
2464 switch (this_c) {
2465 case CTRL('b'):
2466 case KEY_PPAGE:
2467 if (current > 0)
2468 current -= (page_size - 1);
2469 else
2470 beep();
2471 break;
2473 case CTRL('f'):
2474 case KEY_NPAGE:
2475 if (current < (max_colors - 1))
2476 current += (page_size - 1);
2477 else
2478 beep();
2479 break;
2481 case CTRL('p'):
2482 case KEY_UP:
2483 current = (current == 0 ? (max_colors - 1) : current - 1);
2484 break;
2486 case CTRL('n'):
2487 case KEY_DOWN:
2488 current = (current == (max_colors - 1) ? 0 : current + 1);
2489 break;
2491 case KEY_RIGHT:
2492 field = (field == 2 ? 0 : field + 1);
2493 break;
2495 case KEY_LEFT:
2496 field = (field == 0 ? 2 : field - 1);
2497 break;
2499 case '0':
2500 case '1':
2501 case '2':
2502 case '3':
2503 case '4':
2504 case '5':
2505 case '6':
2506 case '7':
2507 case '8':
2508 case '9':
2509 value = value * 10 + (this_c - '0');
2510 break;
2512 case '+':
2513 change_color((short) current, field, value, 1);
2514 break;
2516 case '-':
2517 change_color((short) current, field, -value, 1);
2518 break;
2520 case '=':
2521 change_color((short) current, field, value, 0);
2522 break;
2524 case '?':
2525 erase();
2526 P(" RGB Value Editing Help");
2527 P("");
2528 P("You are in the RGB value editor. Use the arrow keys to select one of");
2529 P("the fields in one of the RGB triples of the current colors; the one");
2530 P("currently selected will be reverse-video highlighted.");
2531 P("");
2532 P("To change a field, enter the digits of the new value; they are echoed");
2533 P("as entered. Finish by typing `='. The change will take effect instantly.");
2534 P("To increment or decrement a value, use the same procedure, but finish");
2535 P("with a `+' or `-'.");
2536 P("");
2537 P("Press 'm' to invoke the top-level menu with the current color settings.");
2538 P("To quit, do ESC");
2540 Pause();
2541 erase();
2542 break;
2544 case 'm':
2545 endwin();
2546 main_menu(FALSE);
2547 for (i = 0; i < max_colors; i++)
2548 init_pair((short) i, (short) COLOR_WHITE, (short) i);
2549 refresh();
2550 break;
2552 case case_QUIT:
2553 break;
2555 default:
2556 beep();
2557 break;
2560 if (current < 0)
2561 current = 0;
2562 if (current >= max_colors)
2563 current = max_colors - 1;
2564 if (current < top_color)
2565 top_color = current;
2566 if (current - top_color >= page_size)
2567 top_color = current - (page_size - 1);
2569 MvPrintw(LINES - 1, 0, "Number: %d", value);
2570 clrtoeol();
2571 } while
2572 (!isQuit(this_c));
2574 erase();
2577 * ncurses does not reset each color individually when calling endwin().
2579 init_all_colors();
2581 endwin();
2584 /****************************************************************************
2586 * Alternate character-set stuff
2588 ****************************************************************************/
2589 /* *INDENT-OFF* */
2590 static struct {
2591 chtype attr;
2592 const char *name;
2593 } attrs_to_cycle[] = {
2594 { A_NORMAL, "normal" },
2595 { A_BOLD, "bold" },
2596 { A_BLINK, "blink" },
2597 { A_REVERSE, "reverse" },
2598 { A_UNDERLINE, "underline" },
2600 /* *INDENT-ON* */
2602 static bool
2603 cycle_attr(int ch, unsigned *at_code, chtype *attr)
2605 bool result = TRUE;
2607 switch (ch) {
2608 case 'v':
2609 if ((*at_code += 1) >= SIZEOF(attrs_to_cycle))
2610 *at_code = 0;
2611 break;
2612 case 'V':
2613 if (*at_code == 0)
2614 *at_code = SIZEOF(attrs_to_cycle) - 1;
2615 else
2616 *at_code -= 1;
2617 break;
2618 default:
2619 result = FALSE;
2620 break;
2622 if (result)
2623 *attr = attrs_to_cycle[*at_code].attr;
2624 return result;
2627 static bool
2628 cycle_colors(int ch, int *fg, int *bg, short *pair)
2630 bool result = FALSE;
2632 if (use_colors) {
2633 result = TRUE;
2634 switch (ch) {
2635 case 'F':
2636 if ((*fg -= 1) < 0)
2637 *fg = COLORS - 1;
2638 break;
2639 case 'f':
2640 if ((*fg += 1) >= COLORS)
2641 *fg = 0;
2642 break;
2643 case 'B':
2644 if ((*bg -= 1) < 0)
2645 *bg = COLORS - 1;
2646 break;
2647 case 'b':
2648 if ((*bg += 1) >= COLORS)
2649 *bg = 0;
2650 break;
2651 default:
2652 result = FALSE;
2653 break;
2655 if (result) {
2656 *pair = (short) (*fg != COLOR_BLACK || *bg != COLOR_BLACK);
2657 if (*pair != 0) {
2658 *pair = 1;
2659 if (init_pair(*pair, (short) *fg, (short) *bg) == ERR) {
2660 result = FALSE;
2665 return result;
2668 /****************************************************************************
2670 * Soft-key label test
2672 ****************************************************************************/
2674 #if USE_SOFTKEYS
2676 #define SLK_HELP 17
2677 #define SLK_WORK (SLK_HELP + 3)
2679 static void
2680 slk_help(void)
2682 static const char *table[] =
2684 "Available commands are:"
2686 ,"^L -- repaint this message and activate soft keys"
2687 ,"a/d -- activate/disable soft keys"
2688 ,"c -- set centered format for labels"
2689 ,"l -- set left-justified format for labels"
2690 ,"r -- set right-justified format for labels"
2691 ,"[12345678] -- set label; labels are numbered 1 through 8"
2692 ,"e -- erase stdscr (should not erase labels)"
2693 ,"s -- test scrolling of shortened screen"
2694 ,"v/V -- cycle through video attributes"
2695 #if HAVE_SLK_COLOR
2696 ,"F/f/B/b -- cycle through foreground/background colors"
2697 #endif
2698 ,"ESC -- return to main menu"
2700 ,"Note: if activating the soft keys causes your terminal to scroll up"
2701 ,"one line, your terminal auto-scrolls when anything is written to the"
2702 ,"last screen position. The ncurses code does not yet handle this"
2703 ,"gracefully."
2705 unsigned j;
2707 move(2, 0);
2708 for (j = 0; j < SIZEOF(table); ++j) {
2709 P(table[j]);
2711 refresh();
2714 #if HAVE_SLK_COLOR
2715 static void
2716 call_slk_color(int fg, int bg)
2718 init_pair(1, (short) bg, (short) fg);
2719 slk_color(1);
2720 MvPrintw(SLK_WORK, 0, "Colors %d/%d\n", fg, bg);
2721 clrtoeol();
2722 slk_touch();
2723 slk_noutrefresh();
2724 refresh();
2726 #endif
2728 static void
2729 slk_test(void)
2730 /* exercise the soft keys */
2732 int c, fmt = 1;
2733 char buf[9];
2734 char *s;
2735 chtype attr = A_NORMAL;
2736 unsigned at_code = 0;
2737 #if HAVE_SLK_COLOR
2738 int fg = COLOR_BLACK;
2739 int bg = COLOR_WHITE;
2740 short pair = 0;
2741 #endif
2743 c = CTRL('l');
2744 #if HAVE_SLK_COLOR
2745 if (use_colors) {
2746 call_slk_color(fg, bg);
2748 #endif
2750 do {
2751 move(0, 0);
2752 switch (c) {
2753 case CTRL('l'):
2754 erase();
2755 attron(A_BOLD);
2756 MvAddStr(0, 20, "Soft Key Exerciser");
2757 attroff(A_BOLD);
2759 slk_help();
2760 /* fall through */
2762 case 'a':
2763 slk_restore();
2764 break;
2766 case 'e':
2767 wclear(stdscr);
2768 break;
2770 case 's':
2771 MvPrintw(SLK_WORK, 0, "Press Q to stop the scrolling-test: ");
2772 while ((c = Getchar()) != 'Q' && (c != ERR))
2773 addch((chtype) c);
2774 break;
2776 case 'd':
2777 slk_clear();
2778 break;
2780 case 'l':
2781 fmt = 0;
2782 break;
2784 case 'c':
2785 fmt = 1;
2786 break;
2788 case 'r':
2789 fmt = 2;
2790 break;
2792 case '1':
2793 case '2':
2794 case '3':
2795 case '4':
2796 case '5':
2797 case '6':
2798 case '7':
2799 case '8':
2800 MvAddStr(SLK_WORK, 0, "Please enter the label value: ");
2801 strcpy(buf, "");
2802 if ((s = slk_label(c - '0')) != 0) {
2803 strncpy(buf, s, 8);
2805 wGetstring(stdscr, buf, 8);
2806 slk_set((c - '0'), buf, fmt);
2807 slk_refresh();
2808 move(SLK_WORK, 0);
2809 clrtobot();
2810 break;
2812 case case_QUIT:
2813 goto done;
2815 #if defined(NCURSES_VERSION) && defined(KEY_RESIZE) && HAVE_WRESIZE
2816 case KEY_RESIZE:
2817 wnoutrefresh(stdscr);
2818 break;
2819 #endif
2821 default:
2822 if (cycle_attr(c, &at_code, &attr)) {
2823 slk_attrset(attr);
2824 slk_touch();
2825 slk_noutrefresh();
2826 break;
2828 #if HAVE_SLK_COLOR
2829 if (cycle_colors(c, &fg, &bg, &pair)) {
2830 if (use_colors) {
2831 call_slk_color(fg, bg);
2832 } else {
2833 beep();
2835 break;
2837 #endif
2838 beep();
2839 break;
2841 } while (!isQuit(c = Getchar()));
2843 done:
2844 slk_clear();
2845 erase();
2846 endwin();
2849 #if USE_WIDEC_SUPPORT
2850 #define SLKLEN 8
2851 static void
2852 wide_slk_test(void)
2853 /* exercise the soft keys */
2855 int c, fmt = 1;
2856 wchar_t buf[SLKLEN + 1];
2857 char *s;
2858 chtype attr = A_NORMAL;
2859 unsigned at_code = 0;
2860 int fg = COLOR_BLACK;
2861 int bg = COLOR_WHITE;
2862 short pair = 0;
2864 c = CTRL('l');
2865 if (use_colors) {
2866 call_slk_color(fg, bg);
2868 do {
2869 move(0, 0);
2870 switch (c) {
2871 case CTRL('l'):
2872 erase();
2873 attr_on(WA_BOLD, NULL);
2874 MvAddStr(0, 20, "Soft Key Exerciser");
2875 attr_off(WA_BOLD, NULL);
2877 slk_help();
2878 /* fall through */
2880 case 'a':
2881 slk_restore();
2882 break;
2884 case 'e':
2885 wclear(stdscr);
2886 break;
2888 case 's':
2889 MvPrintw(SLK_WORK, 0, "Press Q to stop the scrolling-test: ");
2890 while ((c = Getchar()) != 'Q' && (c != ERR))
2891 addch((chtype) c);
2892 break;
2894 case 'd':
2895 slk_clear();
2896 break;
2898 case 'l':
2899 fmt = 0;
2900 break;
2902 case 'c':
2903 fmt = 1;
2904 break;
2906 case 'r':
2907 fmt = 2;
2908 break;
2910 case '1':
2911 case '2':
2912 case '3':
2913 case '4':
2914 case '5':
2915 case '6':
2916 case '7':
2917 case '8':
2918 MvAddStr(SLK_WORK, 0, "Please enter the label value: ");
2919 *buf = 0;
2920 if ((s = slk_label(c - '0')) != 0) {
2921 char *temp = strdup(s);
2922 size_t used = strlen(temp);
2923 size_t want = SLKLEN;
2924 size_t test;
2925 #ifndef state_unused
2926 mbstate_t state;
2927 #endif
2929 buf[0] = L'\0';
2930 while (want > 0 && used != 0) {
2931 const char *base = s;
2932 reset_mbytes(state);
2933 test = count_mbytes(base, 0, &state);
2934 if (test == (size_t) -1) {
2935 temp[--used] = 0;
2936 } else if (test > want) {
2937 temp[--used] = 0;
2938 } else {
2939 reset_mbytes(state);
2940 trans_mbytes(buf, base, want, &state);
2941 break;
2944 free(temp);
2946 wGet_wstring(stdscr, buf, SLKLEN);
2947 slk_wset((c - '0'), buf, fmt);
2948 slk_refresh();
2949 move(SLK_WORK, 0);
2950 clrtobot();
2951 break;
2953 case case_QUIT:
2954 goto done;
2956 case 'F':
2957 if (use_colors) {
2958 fg = (short) ((fg + 1) % COLORS);
2959 call_slk_color(fg, bg);
2961 break;
2962 case 'B':
2963 if (use_colors) {
2964 bg = (short) ((bg + 1) % COLORS);
2965 call_slk_color(fg, bg);
2967 break;
2968 #if defined(NCURSES_VERSION) && defined(KEY_RESIZE) && HAVE_WRESIZE
2969 case KEY_RESIZE:
2970 wnoutrefresh(stdscr);
2971 break;
2972 #endif
2973 default:
2974 if (cycle_attr(c, &at_code, &attr)) {
2975 slk_attr_set(attr, (fg || bg), NULL);
2976 slk_touch();
2977 slk_noutrefresh();
2978 break;
2980 #if HAVE_SLK_COLOR
2981 if (cycle_colors(c, &fg, &bg, &pair)) {
2982 if (use_colors) {
2983 call_slk_color(fg, bg);
2984 } else {
2985 beep();
2987 break;
2989 #endif
2990 beep();
2991 break;
2993 } while (!isQuit(c = Getchar()));
2995 done:
2996 slk_clear();
2997 erase();
2998 endwin();
3000 #endif
3001 #endif /* SLK_INIT */
3003 /* ISO 6429: codes 0x80 to 0x9f may be control characters that cause the
3004 * terminal to perform functions. The remaining codes can be graphic.
3006 static void
3007 show_upper_chars(unsigned first, int repeat, attr_t attr, short pair)
3009 bool C1 = (first == 128);
3010 unsigned code;
3011 unsigned last = first + 31;
3012 int reply;
3014 erase();
3015 attron(A_BOLD);
3016 MvPrintw(0, 20, "Display of %s Character Codes %d to %d",
3017 C1 ? "C1" : "GR", first, last);
3018 attroff(A_BOLD);
3019 refresh();
3021 for (code = first; code <= last; code++) {
3022 int count = repeat;
3023 int row = 2 + ((int) (code - first) % 16);
3024 int col = ((int) (code - first) / 16) * COLS / 2;
3025 char tmp[80];
3026 sprintf(tmp, "%3u (0x%x)", code, code);
3027 MvPrintw(row, col, "%*s: ", COLS / 4, tmp);
3029 do {
3030 if (C1)
3031 nodelay(stdscr, TRUE);
3032 echochar(colored_chtype(code, attr, pair));
3033 if (C1) {
3034 /* (yes, this _is_ crude) */
3035 while ((reply = Getchar()) != ERR) {
3036 addch(UChar(reply));
3037 napms(10);
3039 nodelay(stdscr, FALSE);
3041 } while (--count > 0);
3045 #define PC_COLS 4
3047 static void
3048 show_pc_chars(int repeat, attr_t attr, short pair)
3050 unsigned code;
3052 erase();
3053 attron(A_BOLD);
3054 MvPrintw(0, 20, "Display of PC Character Codes");
3055 attroff(A_BOLD);
3056 refresh();
3058 for (code = 0; code < 16; ++code) {
3059 MvPrintw(2, (int) code * PC_COLS + 8, "%X", code);
3061 for (code = 0; code < 256; code++) {
3062 int count = repeat;
3063 int row = 3 + (int) (code / 16) + (code >= 128);
3064 int col = 8 + (int) (code % 16) * PC_COLS;
3065 if ((code % 16) == 0)
3066 MvPrintw(row, 0, "0x%02x:", code);
3067 move(row, col);
3068 do {
3069 switch (code) {
3070 case '\n':
3071 case '\r':
3072 case '\b':
3073 case '\f':
3074 case '\033':
3075 case 0x9b:
3077 * Skip the ones that do not work.
3079 break;
3080 default:
3081 addch(colored_chtype(code, A_ALTCHARSET | attr, pair));
3082 break;
3084 } while (--count > 0);
3088 static void
3089 show_box_chars(int repeat, attr_t attr, short pair)
3091 (void) repeat;
3093 attr |= (attr_t) COLOR_PAIR(pair);
3095 erase();
3096 attron(A_BOLD);
3097 MvAddStr(0, 20, "Display of the ACS Line-Drawing Set");
3098 attroff(A_BOLD);
3099 refresh();
3100 /* *INDENT-OFF* */
3101 wborder(stdscr,
3102 colored_chtype(ACS_VLINE, attr, pair),
3103 colored_chtype(ACS_VLINE, attr, pair),
3104 colored_chtype(ACS_HLINE, attr, pair),
3105 colored_chtype(ACS_HLINE, attr, pair),
3106 colored_chtype(ACS_ULCORNER, attr, pair),
3107 colored_chtype(ACS_URCORNER, attr, pair),
3108 colored_chtype(ACS_LLCORNER, attr, pair),
3109 colored_chtype(ACS_LRCORNER, attr, pair));
3110 MvHLine(LINES / 2, 0, colored_chtype(ACS_HLINE, attr, pair), COLS);
3111 MvVLine(0, COLS / 2, colored_chtype(ACS_VLINE, attr, pair), LINES);
3112 MvAddCh(0, COLS / 2, colored_chtype(ACS_TTEE, attr, pair));
3113 MvAddCh(LINES / 2, COLS / 2, colored_chtype(ACS_PLUS, attr, pair));
3114 MvAddCh(LINES - 1, COLS / 2, colored_chtype(ACS_BTEE, attr, pair));
3115 MvAddCh(LINES / 2, 0, colored_chtype(ACS_LTEE, attr, pair));
3116 MvAddCh(LINES / 2, COLS - 1, colored_chtype(ACS_RTEE, attr, pair));
3117 /* *INDENT-ON* */
3121 static int
3122 show_1_acs(int n, int repeat, const char *name, chtype code)
3124 const int height = 16;
3125 int row = 2 + (n % height);
3126 int col = (n / height) * COLS / 2;
3128 MvPrintw(row, col, "%*s : ", COLS / 4, name);
3129 do {
3130 addch(code);
3131 } while (--repeat > 0);
3132 return n + 1;
3135 static void
3136 show_acs_chars(int repeat, attr_t attr, short pair)
3137 /* display the ACS character set */
3139 int n;
3141 #define BOTH(name) #name, colored_chtype(name, attr, (chtype) pair)
3143 erase();
3144 attron(A_BOLD);
3145 MvAddStr(0, 20, "Display of the ACS Character Set");
3146 attroff(A_BOLD);
3147 refresh();
3149 n = show_1_acs(0, repeat, BOTH(ACS_ULCORNER));
3150 n = show_1_acs(n, repeat, BOTH(ACS_URCORNER));
3151 n = show_1_acs(n, repeat, BOTH(ACS_LLCORNER));
3152 n = show_1_acs(n, repeat, BOTH(ACS_LRCORNER));
3154 n = show_1_acs(n, repeat, BOTH(ACS_LTEE));
3155 n = show_1_acs(n, repeat, BOTH(ACS_RTEE));
3156 n = show_1_acs(n, repeat, BOTH(ACS_TTEE));
3157 n = show_1_acs(n, repeat, BOTH(ACS_BTEE));
3159 n = show_1_acs(n, repeat, BOTH(ACS_HLINE));
3160 n = show_1_acs(n, repeat, BOTH(ACS_VLINE));
3163 * HPUX's ACS definitions are broken here. Just give up.
3165 #if !(defined(__hpux) && !defined(NCURSES_VERSION))
3166 n = show_1_acs(n, repeat, BOTH(ACS_LARROW));
3167 n = show_1_acs(n, repeat, BOTH(ACS_RARROW));
3168 n = show_1_acs(n, repeat, BOTH(ACS_UARROW));
3169 n = show_1_acs(n, repeat, BOTH(ACS_DARROW));
3171 n = show_1_acs(n, repeat, BOTH(ACS_BLOCK));
3172 n = show_1_acs(n, repeat, BOTH(ACS_BOARD));
3173 n = show_1_acs(n, repeat, BOTH(ACS_LANTERN));
3174 n = show_1_acs(n, repeat, BOTH(ACS_BULLET));
3175 n = show_1_acs(n, repeat, BOTH(ACS_CKBOARD));
3176 n = show_1_acs(n, repeat, BOTH(ACS_DEGREE));
3177 n = show_1_acs(n, repeat, BOTH(ACS_DIAMOND));
3178 n = show_1_acs(n, repeat, BOTH(ACS_PLMINUS));
3179 n = show_1_acs(n, repeat, BOTH(ACS_PLUS));
3181 n = show_1_acs(n, repeat, BOTH(ACS_GEQUAL));
3182 n = show_1_acs(n, repeat, BOTH(ACS_NEQUAL));
3183 n = show_1_acs(n, repeat, BOTH(ACS_LEQUAL));
3185 n = show_1_acs(n, repeat, BOTH(ACS_STERLING));
3186 n = show_1_acs(n, repeat, BOTH(ACS_PI));
3187 n = show_1_acs(n, repeat, BOTH(ACS_S1));
3188 n = show_1_acs(n, repeat, BOTH(ACS_S3));
3189 n = show_1_acs(n, repeat, BOTH(ACS_S7));
3190 (void) show_1_acs(n, repeat, BOTH(ACS_S9));
3191 #endif
3194 static void
3195 acs_display(void)
3197 int c = 'a';
3198 char *term = getenv("TERM");
3199 const char *pch_kludge = ((term != 0 && strstr(term, "linux"))
3200 ? "p=PC, "
3201 : "");
3202 chtype attr = A_NORMAL;
3203 int digit = 0;
3204 int repeat = 1;
3205 int fg = COLOR_BLACK;
3206 int bg = COLOR_BLACK;
3207 unsigned at_code = 0;
3208 short pair = 0;
3209 void (*last_show_acs) (int, attr_t, short) = 0;
3211 do {
3212 switch (c) {
3213 case CTRL('L'):
3214 Repaint();
3215 break;
3216 case 'a':
3217 ToggleAcs(last_show_acs, show_acs_chars);
3218 break;
3219 case 'p':
3220 if (*pch_kludge)
3221 ToggleAcs(last_show_acs, show_pc_chars);
3222 else
3223 beep();
3224 break;
3225 case 'x':
3226 ToggleAcs(last_show_acs, show_box_chars);
3227 break;
3228 case '0':
3229 case '1':
3230 case '2':
3231 case '3':
3232 digit = (c - '0');
3233 last_show_acs = 0;
3234 break;
3235 case '-':
3236 if (digit > 0) {
3237 --digit;
3238 last_show_acs = 0;
3239 } else {
3240 beep();
3242 break;
3243 case '+':
3244 if (digit < 3) {
3245 ++digit;
3246 last_show_acs = 0;
3247 } else {
3248 beep();
3250 break;
3251 case '>':
3252 if (repeat < (COLS / 4))
3253 ++repeat;
3254 break;
3255 case '<':
3256 if (repeat > 1)
3257 --repeat;
3258 break;
3259 default:
3260 if (cycle_attr(c, &at_code, &attr)
3261 || cycle_colors(c, &fg, &bg, &pair)) {
3262 break;
3263 } else {
3264 beep();
3266 break;
3268 if (last_show_acs != 0)
3269 last_show_acs(repeat, attr, pair);
3270 else
3271 show_upper_chars((unsigned) (digit * 32 + 128), repeat, attr, pair);
3273 MvPrintw(LINES - 3, 0,
3274 "Note: ANSI terminals may not display C1 characters.");
3275 MvPrintw(LINES - 2, 0,
3276 "Select: a=ACS, x=box, %s0=C1, 1-3,+/- non-ASCII, </> repeat, ESC=quit",
3277 pch_kludge);
3278 if (use_colors) {
3279 MvPrintw(LINES - 1, 0,
3280 "v/V, f/F, b/B cycle through video attributes (%s) and color %d/%d.",
3281 attrs_to_cycle[at_code].name,
3282 fg, bg);
3283 } else {
3284 MvPrintw(LINES - 1, 0,
3285 "v/V cycles through video attributes (%s).",
3286 attrs_to_cycle[at_code].name);
3288 refresh();
3289 } while (!isQuit(c = Getchar()));
3291 Pause();
3292 erase();
3293 endwin();
3296 #if USE_WIDEC_SUPPORT
3297 static cchar_t *
3298 merge_wide_attr(cchar_t *dst, const cchar_t *src, attr_t attr, short pair)
3300 int count;
3302 *dst = *src;
3303 do {
3304 TEST_CCHAR(src, count, {
3305 attr |= (test_attrs & A_ALTCHARSET);
3306 setcchar(dst, test_wch, attr, pair, NULL);
3311 } while (0);
3312 return dst;
3315 static void
3316 show_upper_widechars(int first, int repeat, int space, attr_t attr, short pair)
3318 cchar_t temp;
3319 wchar_t code;
3320 int last = first + 31;
3322 erase();
3323 attron(A_BOLD);
3324 MvPrintw(0, 20, "Display of Character Codes %d to %d", first, last);
3325 attroff(A_BOLD);
3327 for (code = first; (int) code <= last; code++) {
3328 int row = 2 + ((code - first) % 16);
3329 int col = ((code - first) / 16) * COLS / 2;
3330 wchar_t codes[10];
3331 char tmp[80];
3332 int count = repeat;
3333 int y, x;
3335 memset(&codes, 0, sizeof(codes));
3336 codes[0] = code;
3337 sprintf(tmp, "%3ld (0x%lx)", (long) code, (long) code);
3338 MvPrintw(row, col, "%*s: ", COLS / 4, tmp);
3339 setcchar(&temp, codes, attr, pair, 0);
3340 do {
3342 * Give non-spacing characters something to combine with. If we
3343 * don't, they'll bunch up in a heap on the space after the ":".
3344 * Mark them with reverse-video to make them simpler to find on
3345 * the display.
3347 if (wcwidth(code) == 0) {
3348 addch((chtype) space |
3349 (A_REVERSE ^ attr) |
3350 (attr_t) COLOR_PAIR(pair));
3353 * This could use add_wch(), but is done for comparison with the
3354 * normal 'f' test (and to make a test-case for echo_wchar()).
3355 * The screen will flicker because the erase() at the top of the
3356 * function is met by the builtin refresh() in echo_wchar().
3358 echo_wchar(&temp);
3360 * The repeat-count may make text wrap - avoid that.
3362 getyx(stdscr, y, x);
3363 if (x >= col + (COLS / 2) - 2)
3364 break;
3365 } while (--count > 0);
3369 static int
3370 show_1_wacs(int n, int repeat, const char *name, const cchar_t *code)
3372 const int height = 16;
3373 int row = 2 + (n % height);
3374 int col = (n / height) * COLS / 2;
3376 MvPrintw(row, col, "%*s : ", COLS / 4, name);
3377 while (--repeat >= 0) {
3378 add_wch(code);
3380 return n + 1;
3383 #define MERGE_ATTR(wch) merge_wide_attr(&temp, wch, attr, pair)
3385 static void
3386 show_wacs_chars(int repeat, attr_t attr, short pair)
3387 /* display the wide-ACS character set */
3389 cchar_t temp;
3391 int n;
3393 /*#define BOTH2(name) #name, &(name) */
3394 #define BOTH2(name) #name, MERGE_ATTR(name)
3396 erase();
3397 attron(A_BOLD);
3398 MvAddStr(0, 20, "Display of the Wide-ACS Character Set");
3399 attroff(A_BOLD);
3400 refresh();
3402 n = show_1_wacs(0, repeat, BOTH2(WACS_ULCORNER));
3403 n = show_1_wacs(n, repeat, BOTH2(WACS_URCORNER));
3404 n = show_1_wacs(n, repeat, BOTH2(WACS_LLCORNER));
3405 n = show_1_wacs(n, repeat, BOTH2(WACS_LRCORNER));
3407 n = show_1_wacs(n, repeat, BOTH2(WACS_LTEE));
3408 n = show_1_wacs(n, repeat, BOTH2(WACS_RTEE));
3409 n = show_1_wacs(n, repeat, BOTH2(WACS_TTEE));
3410 n = show_1_wacs(n, repeat, BOTH2(WACS_BTEE));
3412 n = show_1_wacs(n, repeat, BOTH2(WACS_HLINE));
3413 n = show_1_wacs(n, repeat, BOTH2(WACS_VLINE));
3415 n = show_1_wacs(n, repeat, BOTH2(WACS_LARROW));
3416 n = show_1_wacs(n, repeat, BOTH2(WACS_RARROW));
3417 n = show_1_wacs(n, repeat, BOTH2(WACS_UARROW));
3418 n = show_1_wacs(n, repeat, BOTH2(WACS_DARROW));
3420 n = show_1_wacs(n, repeat, BOTH2(WACS_BLOCK));
3421 n = show_1_wacs(n, repeat, BOTH2(WACS_BOARD));
3422 n = show_1_wacs(n, repeat, BOTH2(WACS_LANTERN));
3423 n = show_1_wacs(n, repeat, BOTH2(WACS_BULLET));
3424 n = show_1_wacs(n, repeat, BOTH2(WACS_CKBOARD));
3425 n = show_1_wacs(n, repeat, BOTH2(WACS_DEGREE));
3426 n = show_1_wacs(n, repeat, BOTH2(WACS_DIAMOND));
3427 n = show_1_wacs(n, repeat, BOTH2(WACS_PLMINUS));
3428 n = show_1_wacs(n, repeat, BOTH2(WACS_PLUS));
3430 #ifdef CURSES_WACS_ARRAY
3431 n = show_1_wacs(n, repeat, BOTH2(WACS_GEQUAL));
3432 n = show_1_wacs(n, repeat, BOTH2(WACS_NEQUAL));
3433 n = show_1_wacs(n, repeat, BOTH2(WACS_LEQUAL));
3435 n = show_1_wacs(n, repeat, BOTH2(WACS_STERLING));
3436 n = show_1_wacs(n, repeat, BOTH2(WACS_PI));
3437 n = show_1_wacs(n, repeat, BOTH2(WACS_S1));
3438 n = show_1_wacs(n, repeat, BOTH2(WACS_S3));
3439 n = show_1_wacs(n, repeat, BOTH2(WACS_S7));
3440 (void) show_1_wacs(n, repeat, BOTH2(WACS_S9));
3441 #endif
3444 #ifdef WACS_D_PLUS
3445 static void
3446 show_wacs_chars_double(int repeat, attr_t attr, short pair)
3447 /* display the wide-ACS character set */
3449 cchar_t temp;
3451 int n;
3453 /*#define BOTH2(name) #name, &(name) */
3454 #define BOTH2(name) #name, MERGE_ATTR(name)
3456 erase();
3457 attron(A_BOLD);
3458 MvAddStr(0, 20, "Display of the Wide-ACS Character Set");
3459 attroff(A_BOLD);
3460 refresh();
3462 n = show_1_wacs(0, repeat, BOTH2(WACS_D_ULCORNER));
3463 n = show_1_wacs(n, repeat, BOTH2(WACS_D_URCORNER));
3464 n = show_1_wacs(n, repeat, BOTH2(WACS_D_LLCORNER));
3465 n = show_1_wacs(n, repeat, BOTH2(WACS_D_LRCORNER));
3467 n = show_1_wacs(n, repeat, BOTH2(WACS_D_LTEE));
3468 n = show_1_wacs(n, repeat, BOTH2(WACS_D_RTEE));
3469 n = show_1_wacs(n, repeat, BOTH2(WACS_D_TTEE));
3470 n = show_1_wacs(n, repeat, BOTH2(WACS_D_BTEE));
3472 n = show_1_wacs(n, repeat, BOTH2(WACS_D_HLINE));
3473 n = show_1_wacs(n, repeat, BOTH2(WACS_D_VLINE));
3475 n = show_1_wacs(n, repeat, BOTH2(WACS_LARROW));
3476 n = show_1_wacs(n, repeat, BOTH2(WACS_RARROW));
3477 n = show_1_wacs(n, repeat, BOTH2(WACS_UARROW));
3478 n = show_1_wacs(n, repeat, BOTH2(WACS_DARROW));
3480 n = show_1_wacs(n, repeat, BOTH2(WACS_BLOCK));
3481 n = show_1_wacs(n, repeat, BOTH2(WACS_BOARD));
3482 n = show_1_wacs(n, repeat, BOTH2(WACS_LANTERN));
3483 n = show_1_wacs(n, repeat, BOTH2(WACS_BULLET));
3484 n = show_1_wacs(n, repeat, BOTH2(WACS_CKBOARD));
3485 n = show_1_wacs(n, repeat, BOTH2(WACS_DEGREE));
3486 n = show_1_wacs(n, repeat, BOTH2(WACS_DIAMOND));
3487 n = show_1_wacs(n, repeat, BOTH2(WACS_PLMINUS));
3488 n = show_1_wacs(n, repeat, BOTH2(WACS_PLUS));
3490 #ifdef CURSES_WACS_ARRAY
3491 n = show_1_wacs(n, repeat, BOTH2(WACS_GEQUAL));
3492 n = show_1_wacs(n, repeat, BOTH2(WACS_NEQUAL));
3493 n = show_1_wacs(n, repeat, BOTH2(WACS_LEQUAL));
3495 n = show_1_wacs(n, repeat, BOTH2(WACS_STERLING));
3496 n = show_1_wacs(n, repeat, BOTH2(WACS_PI));
3497 n = show_1_wacs(n, repeat, BOTH2(WACS_S1));
3498 n = show_1_wacs(n, repeat, BOTH2(WACS_S3));
3499 n = show_1_wacs(n, repeat, BOTH2(WACS_S7));
3500 (void) show_1_wacs(n, repeat, BOTH2(WACS_S9));
3501 #endif
3503 #endif
3505 #ifdef WACS_T_PLUS
3506 static void
3507 show_wacs_chars_thick(int repeat, attr_t attr, short pair)
3508 /* display the wide-ACS character set */
3510 cchar_t temp;
3512 int n;
3514 /*#define BOTH2(name) #name, &(name) */
3515 #define BOTH2(name) #name, MERGE_ATTR(name)
3517 erase();
3518 attron(A_BOLD);
3519 MvAddStr(0, 20, "Display of the Wide-ACS Character Set");
3520 attroff(A_BOLD);
3521 refresh();
3523 n = show_1_wacs(0, repeat, BOTH2(WACS_T_ULCORNER));
3524 n = show_1_wacs(n, repeat, BOTH2(WACS_T_URCORNER));
3525 n = show_1_wacs(n, repeat, BOTH2(WACS_T_LLCORNER));
3526 n = show_1_wacs(n, repeat, BOTH2(WACS_T_LRCORNER));
3528 n = show_1_wacs(n, repeat, BOTH2(WACS_T_LTEE));
3529 n = show_1_wacs(n, repeat, BOTH2(WACS_T_RTEE));
3530 n = show_1_wacs(n, repeat, BOTH2(WACS_T_TTEE));
3531 n = show_1_wacs(n, repeat, BOTH2(WACS_T_BTEE));
3533 n = show_1_wacs(n, repeat, BOTH2(WACS_T_HLINE));
3534 n = show_1_wacs(n, repeat, BOTH2(WACS_T_VLINE));
3536 n = show_1_wacs(n, repeat, BOTH2(WACS_LARROW));
3537 n = show_1_wacs(n, repeat, BOTH2(WACS_RARROW));
3538 n = show_1_wacs(n, repeat, BOTH2(WACS_UARROW));
3539 n = show_1_wacs(n, repeat, BOTH2(WACS_DARROW));
3541 n = show_1_wacs(n, repeat, BOTH2(WACS_BLOCK));
3542 n = show_1_wacs(n, repeat, BOTH2(WACS_BOARD));
3543 n = show_1_wacs(n, repeat, BOTH2(WACS_LANTERN));
3544 n = show_1_wacs(n, repeat, BOTH2(WACS_BULLET));
3545 n = show_1_wacs(n, repeat, BOTH2(WACS_CKBOARD));
3546 n = show_1_wacs(n, repeat, BOTH2(WACS_DEGREE));
3547 n = show_1_wacs(n, repeat, BOTH2(WACS_DIAMOND));
3548 n = show_1_wacs(n, repeat, BOTH2(WACS_PLMINUS));
3549 n = show_1_wacs(n, repeat, BOTH2(WACS_PLUS));
3551 #ifdef CURSES_WACS_ARRAY
3552 n = show_1_wacs(n, repeat, BOTH2(WACS_GEQUAL));
3553 n = show_1_wacs(n, repeat, BOTH2(WACS_NEQUAL));
3554 n = show_1_wacs(n, repeat, BOTH2(WACS_LEQUAL));
3556 n = show_1_wacs(n, repeat, BOTH2(WACS_STERLING));
3557 n = show_1_wacs(n, repeat, BOTH2(WACS_PI));
3558 n = show_1_wacs(n, repeat, BOTH2(WACS_S1));
3559 n = show_1_wacs(n, repeat, BOTH2(WACS_S3));
3560 n = show_1_wacs(n, repeat, BOTH2(WACS_S7));
3561 (void) show_1_wacs(n, repeat, BOTH2(WACS_S9));
3562 #endif
3564 #endif
3566 #undef MERGE_ATTR
3568 #define MERGE_ATTR(n,wch) merge_wide_attr(&temp[n], wch, attr, pair)
3570 static void
3571 show_wbox_chars(int repeat, attr_t attr, short pair)
3573 cchar_t temp[8];
3575 (void) repeat;
3576 erase();
3577 attron(A_BOLD);
3578 MvAddStr(0, 20, "Display of the Wide-ACS Line-Drawing Set");
3579 attroff(A_BOLD);
3580 refresh();
3582 wborder_set(stdscr,
3583 MERGE_ATTR(0, WACS_VLINE),
3584 MERGE_ATTR(1, WACS_VLINE),
3585 MERGE_ATTR(2, WACS_HLINE),
3586 MERGE_ATTR(3, WACS_HLINE),
3587 MERGE_ATTR(4, WACS_ULCORNER),
3588 MERGE_ATTR(5, WACS_URCORNER),
3589 MERGE_ATTR(6, WACS_LLCORNER),
3590 MERGE_ATTR(7, WACS_LRCORNER));
3591 /* *INDENT-OFF* */
3592 (void) mvhline_set(LINES / 2, 0, MERGE_ATTR(0, WACS_HLINE), COLS);
3593 (void) mvvline_set(0, COLS / 2, MERGE_ATTR(0, WACS_VLINE), LINES);
3594 (void) mvadd_wch(0, COLS / 2, MERGE_ATTR(0, WACS_TTEE));
3595 (void) mvadd_wch(LINES / 2, COLS / 2, MERGE_ATTR(0, WACS_PLUS));
3596 (void) mvadd_wch(LINES - 1, COLS / 2, MERGE_ATTR(0, WACS_BTEE));
3597 (void) mvadd_wch(LINES / 2, 0, MERGE_ATTR(0, WACS_LTEE));
3598 (void) mvadd_wch(LINES / 2, COLS - 1, MERGE_ATTR(0, WACS_RTEE));
3599 /* *INDENT-ON* */
3603 #undef MERGE_ATTR
3605 static int
3606 show_2_wacs(int n, const char *name, const char *code, attr_t attr, short pair)
3608 const int height = 16;
3609 int row = 2 + (n % height);
3610 int col = (n / height) * COLS / 2;
3611 char temp[80];
3613 MvPrintw(row, col, "%*s : ", COLS / 4, name);
3614 (void) attr_set(attr, pair, 0);
3615 addstr(strcpy(temp, code));
3616 (void) attr_set(A_NORMAL, 0, 0);
3617 return n + 1;
3620 #define SHOW_UTF8(n, name, code) show_2_wacs(n, name, code, attr, pair)
3622 static void
3623 show_utf8_chars(int repeat, attr_t attr, short pair)
3625 int n;
3627 (void) repeat;
3628 erase();
3629 attron(A_BOLD);
3630 MvAddStr(0, 20, "Display of the Wide-ACS Character Set");
3631 attroff(A_BOLD);
3632 refresh();
3633 /* *INDENT-OFF* */
3634 n = SHOW_UTF8(0, "WACS_ULCORNER", "\342\224\214");
3635 n = SHOW_UTF8(n, "WACS_URCORNER", "\342\224\220");
3636 n = SHOW_UTF8(n, "WACS_LLCORNER", "\342\224\224");
3637 n = SHOW_UTF8(n, "WACS_LRCORNER", "\342\224\230");
3639 n = SHOW_UTF8(n, "WACS_LTEE", "\342\224\234");
3640 n = SHOW_UTF8(n, "WACS_RTEE", "\342\224\244");
3641 n = SHOW_UTF8(n, "WACS_TTEE", "\342\224\254");
3642 n = SHOW_UTF8(n, "WACS_BTEE", "\342\224\264");
3644 n = SHOW_UTF8(n, "WACS_HLINE", "\342\224\200");
3645 n = SHOW_UTF8(n, "WACS_VLINE", "\342\224\202");
3647 n = SHOW_UTF8(n, "WACS_LARROW", "\342\206\220");
3648 n = SHOW_UTF8(n, "WACS_RARROW", "\342\206\222");
3649 n = SHOW_UTF8(n, "WACS_UARROW", "\342\206\221");
3650 n = SHOW_UTF8(n, "WACS_DARROW", "\342\206\223");
3652 n = SHOW_UTF8(n, "WACS_BLOCK", "\342\226\256");
3653 n = SHOW_UTF8(n, "WACS_BOARD", "\342\226\222");
3654 n = SHOW_UTF8(n, "WACS_LANTERN", "\342\230\203");
3655 n = SHOW_UTF8(n, "WACS_BULLET", "\302\267");
3656 n = SHOW_UTF8(n, "WACS_CKBOARD", "\342\226\222");
3657 n = SHOW_UTF8(n, "WACS_DEGREE", "\302\260");
3658 n = SHOW_UTF8(n, "WACS_DIAMOND", "\342\227\206");
3659 n = SHOW_UTF8(n, "WACS_PLMINUS", "\302\261");
3660 n = SHOW_UTF8(n, "WACS_PLUS", "\342\224\274");
3661 n = SHOW_UTF8(n, "WACS_GEQUAL", "\342\211\245");
3662 n = SHOW_UTF8(n, "WACS_NEQUAL", "\342\211\240");
3663 n = SHOW_UTF8(n, "WACS_LEQUAL", "\342\211\244");
3665 n = SHOW_UTF8(n, "WACS_STERLING", "\302\243");
3666 n = SHOW_UTF8(n, "WACS_PI", "\317\200");
3667 n = SHOW_UTF8(n, "WACS_S1", "\342\216\272");
3668 n = SHOW_UTF8(n, "WACS_S3", "\342\216\273");
3669 n = SHOW_UTF8(n, "WACS_S7", "\342\216\274");
3670 (void) SHOW_UTF8(n, "WACS_S9", "\342\216\275");
3671 /* *INDENT-ON* */
3675 /* display the wide-ACS character set */
3676 static void
3677 wide_acs_display(void)
3679 int c = 'a';
3680 int digit = 0;
3681 int repeat = 1;
3682 int space = ' ';
3683 chtype attr = A_NORMAL;
3684 int fg = COLOR_BLACK;
3685 int bg = COLOR_BLACK;
3686 unsigned at_code = 0;
3687 short pair = 0;
3688 void (*last_show_wacs) (int, attr_t, short) = 0;
3690 do {
3691 switch (c) {
3692 case CTRL('L'):
3693 Repaint();
3694 break;
3695 case 'a':
3696 ToggleAcs(last_show_wacs, show_wacs_chars);
3697 break;
3698 #ifdef WACS_D_PLUS
3699 case 'd':
3700 ToggleAcs(last_show_wacs, show_wacs_chars_double);
3701 break;
3702 #endif
3703 #ifdef WACS_T_PLUS
3704 case 't':
3705 ToggleAcs(last_show_wacs, show_wacs_chars_thick);
3706 break;
3707 #endif
3708 case 'x':
3709 ToggleAcs(last_show_wacs, show_wbox_chars);
3710 break;
3711 case 'u':
3712 ToggleAcs(last_show_wacs, show_utf8_chars);
3713 break;
3714 default:
3715 if (c < 256 && isdigit(c)) {
3716 digit = (c - '0');
3717 last_show_wacs = 0;
3718 } else if (c == '+') {
3719 ++digit;
3720 last_show_wacs = 0;
3721 } else if (c == '-' && digit > 0) {
3722 --digit;
3723 last_show_wacs = 0;
3724 } else if (c == '>' && repeat < (COLS / 4)) {
3725 ++repeat;
3726 } else if (c == '<' && repeat > 1) {
3727 --repeat;
3728 } else if (c == '_') {
3729 space = (space == ' ') ? '_' : ' ';
3730 last_show_wacs = 0;
3731 } else if (cycle_attr(c, &at_code, &attr)
3732 || cycle_colors(c, &fg, &bg, &pair)) {
3733 if (last_show_wacs != 0)
3734 break;
3735 } else {
3736 beep();
3737 break;
3739 break;
3741 if (last_show_wacs != 0)
3742 last_show_wacs(repeat, attr, pair);
3743 else
3744 show_upper_widechars(digit * 32 + 128, repeat, space, attr, pair);
3746 MvPrintw(LINES - 3, 0,
3747 "Select: a/d/t WACS, x box, u UTF-8, 0-9,+/- non-ASCII, </> repeat, ESC=quit");
3748 if (use_colors) {
3749 MvPrintw(LINES - 2, 0,
3750 "v/V, f/F, b/B cycle through video attributes (%s) and color %d/%d.",
3751 attrs_to_cycle[at_code].name,
3752 fg, bg);
3753 } else {
3754 MvPrintw(LINES - 2, 0,
3755 "v/V cycles through video attributes (%s).",
3756 attrs_to_cycle[at_code].name);
3758 refresh();
3759 } while (!isQuit(c = Getchar()));
3761 Pause();
3762 erase();
3763 endwin();
3766 #endif
3769 * Graphic-rendition test (adapted from vttest)
3771 static void
3772 test_sgr_attributes(void)
3774 int pass;
3776 for (pass = 0; pass < 2; pass++) {
3777 chtype normal = ((pass == 0 ? A_NORMAL : A_REVERSE)) | BLANK;
3779 /* Use non-default colors if possible to exercise bce a little */
3780 if (use_colors) {
3781 init_pair(1, COLOR_WHITE, COLOR_BLUE);
3782 normal |= COLOR_PAIR(1);
3784 bkgdset(normal);
3785 erase();
3786 MvPrintw(1, 20, "Graphic rendition test pattern:");
3788 MvPrintw(4, 1, "vanilla");
3790 #define set_sgr(mask) bkgdset((normal^(mask)));
3791 set_sgr(A_BOLD);
3792 MvPrintw(4, 40, "bold");
3794 set_sgr(A_UNDERLINE);
3795 MvPrintw(6, 6, "underline");
3797 set_sgr(A_BOLD | A_UNDERLINE);
3798 MvPrintw(6, 45, "bold underline");
3800 set_sgr(A_BLINK);
3801 MvPrintw(8, 1, "blink");
3803 set_sgr(A_BLINK | A_BOLD);
3804 MvPrintw(8, 40, "bold blink");
3806 set_sgr(A_UNDERLINE | A_BLINK);
3807 MvPrintw(10, 6, "underline blink");
3809 set_sgr(A_BOLD | A_UNDERLINE | A_BLINK);
3810 MvPrintw(10, 45, "bold underline blink");
3812 set_sgr(A_REVERSE);
3813 MvPrintw(12, 1, "negative");
3815 set_sgr(A_BOLD | A_REVERSE);
3816 MvPrintw(12, 40, "bold negative");
3818 set_sgr(A_UNDERLINE | A_REVERSE);
3819 MvPrintw(14, 6, "underline negative");
3821 set_sgr(A_BOLD | A_UNDERLINE | A_REVERSE);
3822 MvPrintw(14, 45, "bold underline negative");
3824 set_sgr(A_BLINK | A_REVERSE);
3825 MvPrintw(16, 1, "blink negative");
3827 set_sgr(A_BOLD | A_BLINK | A_REVERSE);
3828 MvPrintw(16, 40, "bold blink negative");
3830 set_sgr(A_UNDERLINE | A_BLINK | A_REVERSE);
3831 MvPrintw(18, 6, "underline blink negative");
3833 set_sgr(A_BOLD | A_UNDERLINE | A_BLINK | A_REVERSE);
3834 MvPrintw(18, 45, "bold underline blink negative");
3836 bkgdset(normal);
3837 MvPrintw(LINES - 2, 1, "%s background. ", pass == 0 ? "Dark" :
3838 "Light");
3839 clrtoeol();
3840 Pause();
3843 bkgdset(A_NORMAL | BLANK);
3844 erase();
3845 endwin();
3848 /****************************************************************************
3850 * Windows and scrolling tester.
3852 ****************************************************************************/
3854 #define BOTLINES 4 /* number of line stolen from screen bottom */
3856 typedef struct {
3857 int y, x;
3858 } pair;
3860 #define FRAME struct frame
3861 FRAME
3863 FRAME *next, *last;
3864 bool do_scroll;
3865 bool do_keypad;
3866 WINDOW *wind;
3869 #if defined(NCURSES_VERSION)
3870 #if (NCURSES_VERSION_PATCH < 20070331) && NCURSES_EXT_FUNCS
3871 #define is_keypad(win) (win)->_use_keypad
3872 #define is_scrollok(win) (win)->_scroll
3873 #elif !defined(is_keypad)
3874 #define is_keypad(win) FALSE
3875 #define is_scrollok(win) FALSE
3876 #endif
3877 #else
3878 #define is_keypad(win) FALSE
3879 #define is_scrollok(win) FALSE
3880 #endif
3882 static WINDOW *
3883 frame_win(FRAME * curp)
3885 return (curp != 0) ? curp->wind : stdscr;
3888 /* We need to know if these flags are actually set, so don't look in FRAME.
3889 * These names are known to work with SVr4 curses as well as ncurses. The
3890 * _use_keypad name does not work with Solaris 8.
3892 static bool
3893 HaveKeypad(FRAME * curp)
3895 WINDOW *win = frame_win(curp);
3896 (void) win;
3897 return is_keypad(win);
3900 static bool
3901 HaveScroll(FRAME * curp)
3903 WINDOW *win = frame_win(curp);
3904 (void) win;
3905 return is_scrollok(win);
3908 static void
3909 newwin_legend(FRAME * curp)
3911 static const struct {
3912 const char *msg;
3913 int code;
3914 } legend[] = {
3916 "^C = create window", 0
3919 "^N = next window", 0
3922 "^P = previous window", 0
3925 "^F = scroll forward", 0
3928 "^B = scroll backward", 0
3931 "^K = keypad(%s)", 1
3934 "^S = scrollok(%s)", 2
3937 "^W = save window to file", 0
3940 "^R = restore window", 0
3942 #if HAVE_WRESIZE
3944 "^X = resize", 0
3946 #endif
3948 "^Q%s = exit", 3
3951 size_t n;
3952 int x;
3953 bool do_keypad = HaveKeypad(curp);
3954 bool do_scroll = HaveScroll(curp);
3955 char buf[BUFSIZ];
3957 move(LINES - 4, 0);
3958 for (n = 0; n < SIZEOF(legend); n++) {
3959 switch (legend[n].code) {
3960 default:
3961 strcpy(buf, legend[n].msg);
3962 break;
3963 case 1:
3964 sprintf(buf, legend[n].msg, do_keypad ? "yes" : "no");
3965 break;
3966 case 2:
3967 sprintf(buf, legend[n].msg, do_scroll ? "yes" : "no");
3968 break;
3969 case 3:
3970 sprintf(buf, legend[n].msg, do_keypad ? "/ESC" : "");
3971 break;
3973 x = getcurx(stdscr);
3974 addstr((COLS < (x + 3 + (int) strlen(buf))) ? "\n" : (n ? ", " : ""));
3975 addstr(buf);
3977 clrtoeol();
3980 static void
3981 transient(FRAME * curp, NCURSES_CONST char *msg)
3983 newwin_legend(curp);
3984 if (msg) {
3985 MvAddStr(LINES - 1, 0, msg);
3986 refresh();
3987 napms(1000);
3990 move(LINES - 1, 0);
3991 printw("%s characters are echoed, window should %sscroll.",
3992 HaveKeypad(curp) ? "Non-arrow" : "All other",
3993 HaveScroll(curp) ? "" : "not ");
3994 clrtoeol();
3997 static void
3998 newwin_report(FRAME * curp)
3999 /* report on the cursor's current position, then restore it */
4001 WINDOW *win = frame_win(curp);
4002 int y, x;
4004 if (win != stdscr)
4005 transient(curp, (char *) 0);
4006 getyx(win, y, x);
4007 move(LINES - 1, COLS - 17);
4008 printw("Y = %2d X = %2d", y, x);
4009 if (win != stdscr)
4010 refresh();
4011 else
4012 wmove(win, y, x);
4015 static pair *
4016 selectcell(int uli, int ulj, int lri, int lrj)
4017 /* arrows keys move cursor, return location at current on non-arrow key */
4019 static pair res; /* result cell */
4020 int si = lri - uli + 1; /* depth of the select area */
4021 int sj = lrj - ulj + 1; /* width of the select area */
4022 int i = 0, j = 0; /* offsets into the select area */
4024 res.y = uli;
4025 res.x = ulj;
4026 for (;;) {
4027 move(uli + i, ulj + j);
4028 newwin_report((FRAME *) 0);
4030 switch (Getchar()) {
4031 case KEY_UP:
4032 i += si - 1;
4033 break;
4034 case KEY_DOWN:
4035 i++;
4036 break;
4037 case KEY_LEFT:
4038 j += sj - 1;
4039 break;
4040 case KEY_RIGHT:
4041 j++;
4042 break;
4043 case case_QUIT:
4044 return ((pair *) 0);
4045 #ifdef NCURSES_MOUSE_VERSION
4046 case KEY_MOUSE:
4048 MEVENT event;
4050 getmouse(&event);
4051 if (event.y > uli && event.x > ulj) {
4052 i = event.y - uli;
4053 j = event.x - ulj;
4054 } else {
4055 beep();
4056 break;
4059 /* FALLTHRU */
4060 #endif
4061 default:
4062 res.y = uli + i;
4063 res.x = ulj + j;
4064 return (&res);
4066 i %= si;
4067 j %= sj;
4071 static void
4072 outerbox(pair ul, pair lr, bool onoff)
4073 /* draw or erase a box *outside* the given pair of corners */
4075 MvAddCh(ul.y - 1, lr.x - 1, onoff ? ACS_ULCORNER : ' ');
4076 MvAddCh(ul.y - 1, lr.x + 1, onoff ? ACS_URCORNER : ' ');
4077 MvAddCh(lr.y + 1, lr.x + 1, onoff ? ACS_LRCORNER : ' ');
4078 MvAddCh(lr.y + 1, ul.x - 1, onoff ? ACS_LLCORNER : ' ');
4079 move(ul.y - 1, ul.x);
4080 hline(onoff ? ACS_HLINE : ' ', lr.x - ul.x + 1);
4081 move(ul.y, ul.x - 1);
4082 vline(onoff ? ACS_VLINE : ' ', lr.y - ul.y + 1);
4083 move(lr.y + 1, ul.x);
4084 hline(onoff ? ACS_HLINE : ' ', lr.x - ul.x + 1);
4085 move(ul.y, lr.x + 1);
4086 vline(onoff ? ACS_VLINE : ' ', lr.y - ul.y + 1);
4089 static WINDOW *
4090 getwindow(void)
4091 /* Ask user for a window definition */
4093 WINDOW *rwindow;
4094 pair ul, lr, *tmp;
4096 move(0, 0);
4097 clrtoeol();
4098 addstr("Use arrows to move cursor, anything else to mark corner 1");
4099 refresh();
4100 if ((tmp = selectcell(2, 1, LINES - BOTLINES - 2, COLS - 2)) == (pair *) 0)
4101 return ((WINDOW *) 0);
4102 memcpy(&ul, tmp, sizeof(pair));
4103 MvAddCh(ul.y - 1, ul.x - 1, ACS_ULCORNER);
4104 move(0, 0);
4105 clrtoeol();
4106 addstr("Use arrows to move cursor, anything else to mark corner 2");
4107 refresh();
4108 if ((tmp = selectcell(ul.y, ul.x, LINES - BOTLINES - 2, COLS - 2)) ==
4109 (pair *) 0)
4110 return ((WINDOW *) 0);
4111 memcpy(&lr, tmp, sizeof(pair));
4113 rwindow = subwin(stdscr, lr.y - ul.y + 1, lr.x - ul.x + 1, ul.y, ul.x);
4115 outerbox(ul, lr, TRUE);
4116 refresh();
4118 wrefresh(rwindow);
4120 move(0, 0);
4121 clrtoeol();
4122 return (rwindow);
4125 static void
4126 newwin_move(FRAME * curp, int dy, int dx)
4128 WINDOW *win = frame_win(curp);
4129 int cur_y, cur_x;
4130 int max_y, max_x;
4132 getyx(win, cur_y, cur_x);
4133 getmaxyx(win, max_y, max_x);
4134 if ((cur_x += dx) < 0)
4135 cur_x = 0;
4136 else if (cur_x >= max_x)
4137 cur_x = max_x - 1;
4138 if ((cur_y += dy) < 0)
4139 cur_y = 0;
4140 else if (cur_y >= max_y)
4141 cur_y = max_y - 1;
4142 wmove(win, cur_y, cur_x);
4145 static FRAME *
4146 delete_framed(FRAME * fp, bool showit)
4148 FRAME *np = 0;
4150 if (fp != 0) {
4151 fp->last->next = fp->next;
4152 fp->next->last = fp->last;
4154 if (showit) {
4155 werase(fp->wind);
4156 wrefresh(fp->wind);
4158 delwin(fp->wind);
4160 np = (fp == fp->next) ? 0 : fp->next;
4161 free(fp);
4163 return np;
4166 static void
4167 acs_and_scroll(void)
4168 /* Demonstrate windows */
4170 int c;
4171 FRAME *current = (FRAME *) 0, *neww;
4172 WINDOW *usescr;
4173 #if HAVE_PUTWIN && HAVE_GETWIN
4174 FILE *fp;
4175 #endif
4177 #define DUMPFILE "screendump"
4179 #ifdef NCURSES_MOUSE_VERSION
4180 mousemask(BUTTON1_CLICKED, (mmask_t *) 0);
4181 #endif
4182 c = CTRL('C');
4183 raw();
4184 do {
4185 transient((FRAME *) 0, (char *) 0);
4186 switch (c) {
4187 case CTRL('C'):
4188 if ((neww = typeCalloc(FRAME, 1)) == 0) {
4189 goto breakout;
4191 if ((neww->wind = getwindow()) == (WINDOW *) 0) {
4192 free(neww);
4193 goto breakout;
4196 if (current == 0) { /* First element, */
4197 neww->next = neww; /* so point it at itself */
4198 neww->last = neww;
4199 } else {
4200 neww->next = current->next;
4201 neww->last = current;
4202 neww->last->next = neww;
4203 neww->next->last = neww;
4205 current = neww;
4206 /* SVr4 curses sets the keypad on all newly-created windows to
4207 * false. Someone reported that PDCurses makes new windows inherit
4208 * this flag. Remove the following 'keypad()' call to test this
4210 keypad(current->wind, TRUE);
4211 current->do_keypad = HaveKeypad(current);
4212 current->do_scroll = HaveScroll(current);
4213 break;
4215 case CTRL('N'): /* go to next window */
4216 if (current)
4217 current = current->next;
4218 break;
4220 case CTRL('P'): /* go to previous window */
4221 if (current)
4222 current = current->last;
4223 break;
4225 case CTRL('F'): /* scroll current window forward */
4226 if (current)
4227 wscrl(frame_win(current), 1);
4228 break;
4230 case CTRL('B'): /* scroll current window backwards */
4231 if (current)
4232 wscrl(frame_win(current), -1);
4233 break;
4235 case CTRL('K'): /* toggle keypad mode for current */
4236 if (current) {
4237 current->do_keypad = !current->do_keypad;
4238 keypad(current->wind, current->do_keypad);
4240 break;
4242 case CTRL('S'):
4243 if (current) {
4244 current->do_scroll = !current->do_scroll;
4245 scrollok(current->wind, current->do_scroll);
4247 break;
4249 #if HAVE_PUTWIN && HAVE_GETWIN
4250 case CTRL('W'): /* save and delete window */
4251 if ((current != 0) && (current == current->next)) {
4252 transient(current, "Will not save/delete ONLY window");
4253 break;
4254 } else if ((fp = fopen(DUMPFILE, "w")) == (FILE *) 0) {
4255 transient(current, "Can't open screen dump file");
4256 } else {
4257 (void) putwin(frame_win(current), fp);
4258 (void) fclose(fp);
4260 current = delete_framed(current, TRUE);
4262 break;
4264 case CTRL('R'): /* restore window */
4265 if ((fp = fopen(DUMPFILE, "r")) == (FILE *) 0) {
4266 transient(current, "Can't open screen dump file");
4267 } else {
4268 if ((neww = typeCalloc(FRAME, 1)) != 0) {
4270 neww->next = current ? current->next : 0;
4271 neww->last = current;
4272 neww->last->next = neww;
4273 neww->next->last = neww;
4275 neww->wind = getwin(fp);
4277 wrefresh(neww->wind);
4279 (void) fclose(fp);
4281 break;
4282 #endif
4284 #if HAVE_WRESIZE
4285 case CTRL('X'): /* resize window */
4286 if (current) {
4287 pair *tmp, ul, lr;
4288 int i, mx, my;
4290 move(0, 0);
4291 clrtoeol();
4292 addstr("Use arrows to move cursor, anything else to mark new corner");
4293 refresh();
4295 getbegyx(current->wind, ul.y, ul.x);
4297 tmp = selectcell(ul.y, ul.x, LINES - BOTLINES - 2, COLS - 2);
4298 if (tmp == (pair *) 0) {
4299 beep();
4300 break;
4303 getmaxyx(current->wind, lr.y, lr.x);
4304 lr.y += (ul.y - 1);
4305 lr.x += (ul.x - 1);
4306 outerbox(ul, lr, FALSE);
4307 wnoutrefresh(stdscr);
4309 /* strictly cosmetic hack for the test */
4310 getmaxyx(current->wind, my, mx);
4311 if (my > tmp->y - ul.y) {
4312 getyx(current->wind, lr.y, lr.x);
4313 wmove(current->wind, tmp->y - ul.y + 1, 0);
4314 wclrtobot(current->wind);
4315 wmove(current->wind, lr.y, lr.x);
4317 if (mx > tmp->x - ul.x)
4318 for (i = 0; i < my; i++) {
4319 wmove(current->wind, i, tmp->x - ul.x + 1);
4320 wclrtoeol(current->wind);
4322 wnoutrefresh(current->wind);
4324 memcpy(&lr, tmp, sizeof(pair));
4325 (void) wresize(current->wind, lr.y - ul.y + 0, lr.x - ul.x + 0);
4327 getbegyx(current->wind, ul.y, ul.x);
4328 getmaxyx(current->wind, lr.y, lr.x);
4329 lr.y += (ul.y - 1);
4330 lr.x += (ul.x - 1);
4331 outerbox(ul, lr, TRUE);
4332 wnoutrefresh(stdscr);
4334 wnoutrefresh(current->wind);
4335 move(0, 0);
4336 clrtoeol();
4337 doupdate();
4339 break;
4340 #endif /* HAVE_WRESIZE */
4342 case KEY_F(10): /* undocumented --- use this to test area clears */
4343 selectcell(0, 0, LINES - 1, COLS - 1);
4344 clrtobot();
4345 refresh();
4346 break;
4348 case KEY_UP:
4349 newwin_move(current, -1, 0);
4350 break;
4351 case KEY_DOWN:
4352 newwin_move(current, 1, 0);
4353 break;
4354 case KEY_LEFT:
4355 newwin_move(current, 0, -1);
4356 break;
4357 case KEY_RIGHT:
4358 newwin_move(current, 0, 1);
4359 break;
4361 case KEY_BACKSPACE:
4362 /* FALLTHROUGH */
4363 case KEY_DC:
4365 int y, x;
4366 getyx(frame_win(current), y, x);
4367 if (--x < 0) {
4368 if (--y < 0)
4369 break;
4370 x = getmaxx(frame_win(current)) - 1;
4372 (void) mvwdelch(frame_win(current), y, x);
4374 break;
4376 case '\r':
4377 c = '\n';
4378 /* FALLTHROUGH */
4380 default:
4381 if (current)
4382 waddch(current->wind, (chtype) c);
4383 else
4384 beep();
4385 break;
4387 newwin_report(current);
4388 usescr = frame_win(current);
4389 wrefresh(usescr);
4390 } while
4391 (!isQuit(c = wGetchar(usescr))
4392 && (c != ERR));
4394 breakout:
4395 while (current != 0)
4396 current = delete_framed(current, FALSE);
4398 scrollok(stdscr, TRUE); /* reset to driver's default */
4399 #ifdef NCURSES_MOUSE_VERSION
4400 mousemask(0, (mmask_t *) 0);
4401 #endif
4402 noraw();
4403 erase();
4404 endwin();
4407 /****************************************************************************
4409 * Panels tester
4411 ****************************************************************************/
4413 #if USE_LIBPANEL
4414 static int nap_msec = 1;
4416 static NCURSES_CONST char *mod[] =
4418 "test ",
4419 "TEST ",
4420 "(**) ",
4421 "*()* ",
4422 "<--> ",
4423 "LAST "
4426 /*+-------------------------------------------------------------------------
4427 wait_a_while(msec)
4428 --------------------------------------------------------------------------*/
4429 static void
4430 wait_a_while(int msec GCC_UNUSED)
4432 #if HAVE_NAPMS
4433 if (nap_msec == 1)
4434 wGetchar(stdscr);
4435 else
4436 napms(nap_msec);
4437 #else
4438 if (nap_msec == 1)
4439 wGetchar(stdscr);
4440 else if (msec > 1000)
4441 sleep((unsigned) msec / 1000);
4442 else
4443 sleep(1);
4444 #endif
4445 } /* end of wait_a_while */
4447 /*+-------------------------------------------------------------------------
4448 saywhat(text)
4449 --------------------------------------------------------------------------*/
4450 static void
4451 saywhat(NCURSES_CONST char *text)
4453 wmove(stdscr, LINES - 1, 0);
4454 wclrtoeol(stdscr);
4455 if (text != 0 && *text != '\0') {
4456 waddstr(stdscr, text);
4457 waddstr(stdscr, "; ");
4459 waddstr(stdscr, "press any key to continue");
4460 } /* end of saywhat */
4462 /*+-------------------------------------------------------------------------
4463 mkpanel(rows,cols,tly,tlx) - alloc a win and panel and associate them
4464 --------------------------------------------------------------------------*/
4465 static PANEL *
4466 mkpanel(short color, int rows, int cols, int tly, int tlx)
4468 WINDOW *win;
4469 PANEL *pan = 0;
4471 if ((win = newwin(rows, cols, tly, tlx)) != 0) {
4472 if ((pan = new_panel(win)) == 0) {
4473 delwin(win);
4474 } else if (use_colors) {
4475 short fg = (short) ((color == COLOR_BLUE) ? COLOR_WHITE : COLOR_BLACK);
4476 short bg = color;
4478 init_pair(color, fg, bg);
4479 wbkgdset(win, (attr_t) (COLOR_PAIR(color) | ' '));
4480 } else {
4481 wbkgdset(win, A_BOLD | ' ');
4484 return pan;
4485 } /* end of mkpanel */
4487 /*+-------------------------------------------------------------------------
4488 rmpanel(pan)
4489 --------------------------------------------------------------------------*/
4490 static void
4491 rmpanel(PANEL * pan)
4493 WINDOW *win = panel_window(pan);
4494 del_panel(pan);
4495 delwin(win);
4496 } /* end of rmpanel */
4498 /*+-------------------------------------------------------------------------
4499 pflush()
4500 --------------------------------------------------------------------------*/
4501 static void
4502 pflush(void)
4504 update_panels();
4505 doupdate();
4506 } /* end of pflush */
4508 /*+-------------------------------------------------------------------------
4509 fill_panel(win)
4510 --------------------------------------------------------------------------*/
4511 static void
4512 init_panel(void)
4514 register int y, x;
4516 for (y = 0; y < LINES - 1; y++) {
4517 for (x = 0; x < COLS; x++)
4518 wprintw(stdscr, "%d", (y + x) % 10);
4522 static void
4523 fill_panel(PANEL * pan)
4525 WINDOW *win = panel_window(pan);
4526 const char *userptr = (const char *) panel_userptr(pan);
4527 int num = (userptr && *userptr) ? userptr[1] : '?';
4528 int y, x;
4530 wmove(win, 1, 1);
4531 wprintw(win, "-pan%c-", num);
4532 wclrtoeol(win);
4533 box(win, 0, 0);
4534 for (y = 2; y < getmaxy(win) - 1; y++) {
4535 for (x = 1; x < getmaxx(win) - 1; x++) {
4536 wmove(win, y, x);
4537 waddch(win, UChar(num));
4542 #if USE_WIDEC_SUPPORT
4543 static void
4544 init_wide_panel(void)
4546 int digit;
4547 cchar_t temp[10];
4549 for (digit = 0; digit < 10; ++digit)
4550 make_fullwidth_digit(&temp[digit], digit);
4552 do {
4553 int y, x;
4554 getyx(stdscr, y, x);
4555 digit = (y + x / 2) % 10;
4556 } while (add_wch(&temp[digit]) != ERR);
4559 static void
4560 fill_wide_panel(PANEL * pan)
4562 WINDOW *win = panel_window(pan);
4563 const char *userptr = (const char *) panel_userptr(pan);
4564 int num = (userptr && *userptr) ? userptr[1] : '?';
4565 int y, x;
4567 wmove(win, 1, 1);
4568 wprintw(win, "-pan%c-", num);
4569 wclrtoeol(win);
4570 box(win, 0, 0);
4571 for (y = 2; y < getmaxy(win) - 1; y++) {
4572 for (x = 1; x < getmaxx(win) - 1; x++) {
4573 wmove(win, y, x);
4574 waddch(win, UChar(num));
4578 #endif
4580 #define MAX_PANELS 5
4582 static void
4583 canned_panel(PANEL * px[MAX_PANELS + 1], NCURSES_CONST char *cmd)
4585 int which = cmd[1] - '0';
4587 saywhat(cmd);
4588 switch (*cmd) {
4589 case 'h':
4590 hide_panel(px[which]);
4591 break;
4592 case 's':
4593 show_panel(px[which]);
4594 break;
4595 case 't':
4596 top_panel(px[which]);
4597 break;
4598 case 'b':
4599 bottom_panel(px[which]);
4600 break;
4601 case 'd':
4602 rmpanel(px[which]);
4603 break;
4605 pflush();
4606 wait_a_while(nap_msec);
4609 static void
4610 demo_panels(void (*InitPanel) (void), void (*FillPanel) (PANEL *))
4612 int count;
4613 int itmp;
4614 PANEL *px[MAX_PANELS + 1];
4616 scrollok(stdscr, FALSE); /* we don't want stdscr to scroll! */
4617 refresh();
4619 InitPanel();
4620 for (count = 0; count < 5; count++) {
4621 px[1] = mkpanel(COLOR_RED,
4622 LINES / 2 - 2,
4623 COLS / 8 + 1,
4626 set_panel_userptr(px[1], (NCURSES_CONST void *) "p1");
4628 px[2] = mkpanel(COLOR_GREEN,
4629 LINES / 2 + 1,
4630 COLS / 7,
4631 LINES / 4,
4632 COLS / 10);
4633 set_panel_userptr(px[2], (NCURSES_CONST void *) "p2");
4635 px[3] = mkpanel(COLOR_YELLOW,
4636 LINES / 4,
4637 COLS / 10,
4638 LINES / 2,
4639 COLS / 9);
4640 set_panel_userptr(px[3], (NCURSES_CONST void *) "p3");
4642 px[4] = mkpanel(COLOR_BLUE,
4643 LINES / 2 - 2,
4644 COLS / 8,
4645 LINES / 2 - 2,
4646 COLS / 3);
4647 set_panel_userptr(px[4], (NCURSES_CONST void *) "p4");
4649 px[5] = mkpanel(COLOR_MAGENTA,
4650 LINES / 2 - 2,
4651 COLS / 8,
4652 LINES / 2,
4653 COLS / 2 - 2);
4654 set_panel_userptr(px[5], (NCURSES_CONST void *) "p5");
4656 FillPanel(px[1]);
4657 FillPanel(px[2]);
4658 FillPanel(px[3]);
4659 FillPanel(px[4]);
4660 FillPanel(px[5]);
4662 hide_panel(px[4]);
4663 hide_panel(px[5]);
4664 pflush();
4665 saywhat("");
4666 wait_a_while(nap_msec);
4668 saywhat("h3 s1 s2 s4 s5");
4669 move_panel(px[1], 0, 0);
4670 hide_panel(px[3]);
4671 show_panel(px[1]);
4672 show_panel(px[2]);
4673 show_panel(px[4]);
4674 show_panel(px[5]);
4675 pflush();
4676 wait_a_while(nap_msec);
4678 canned_panel(px, "s1");
4679 canned_panel(px, "s2");
4681 saywhat("m2");
4682 move_panel(px[2], LINES / 3 + 1, COLS / 8);
4683 pflush();
4684 wait_a_while(nap_msec);
4686 canned_panel(px, "s3");
4688 saywhat("m3");
4689 move_panel(px[3], LINES / 4 + 1, COLS / 15);
4690 pflush();
4691 wait_a_while(nap_msec);
4693 canned_panel(px, "b3");
4694 canned_panel(px, "s4");
4695 canned_panel(px, "s5");
4696 canned_panel(px, "t3");
4697 canned_panel(px, "t1");
4698 canned_panel(px, "t2");
4699 canned_panel(px, "t3");
4700 canned_panel(px, "t4");
4702 for (itmp = 0; itmp < 6; itmp++) {
4703 WINDOW *w4 = panel_window(px[4]);
4704 WINDOW *w5 = panel_window(px[5]);
4706 saywhat("m4");
4707 wmove(w4, LINES / 8, 1);
4708 waddstr(w4, mod[itmp]);
4709 move_panel(px[4], LINES / 6, itmp * (COLS / 8));
4710 wmove(w5, LINES / 6, 1);
4711 waddstr(w5, mod[itmp]);
4712 pflush();
4713 wait_a_while(nap_msec);
4715 saywhat("m5");
4716 wmove(w4, LINES / 6, 1);
4717 waddstr(w4, mod[itmp]);
4718 move_panel(px[5], LINES / 3 - 1, (itmp * 10) + 6);
4719 wmove(w5, LINES / 8, 1);
4720 waddstr(w5, mod[itmp]);
4721 pflush();
4722 wait_a_while(nap_msec);
4725 saywhat("m4");
4726 move_panel(px[4], LINES / 6, itmp * (COLS / 8));
4727 pflush();
4728 wait_a_while(nap_msec);
4730 canned_panel(px, "t5");
4731 canned_panel(px, "t2");
4732 canned_panel(px, "t1");
4733 canned_panel(px, "d2");
4734 canned_panel(px, "h3");
4735 canned_panel(px, "d1");
4736 canned_panel(px, "d4");
4737 canned_panel(px, "d5");
4738 canned_panel(px, "d3");
4740 wait_a_while(nap_msec);
4741 if (nap_msec == 1)
4742 break;
4743 nap_msec = 100L;
4746 erase();
4747 endwin();
4749 #endif /* USE_LIBPANEL */
4751 /****************************************************************************
4753 * Pad tester
4755 ****************************************************************************/
4757 #define GRIDSIZE 3
4759 static bool pending_pan = FALSE;
4760 static bool show_panner_legend = TRUE;
4762 static int
4763 panner_legend(int line)
4765 static const char *const legend[] =
4767 "Use arrow keys (or U,D,L,R) to pan, ESC to quit, ! to shell-out.",
4768 "Use +,- (or j,k) to grow/shrink the panner vertically.",
4769 "Use <,> (or h,l) to grow/shrink the panner horizontally.",
4770 "Number repeats. Toggle legend:? filler:a timer:t scrollmark:s."
4772 int n = ((int) SIZEOF(legend) - (LINES - line));
4773 if (n >= 0) {
4774 if (move(line, 0) != ERR) {
4775 if (show_panner_legend)
4776 printw("%s", legend[n]);
4777 clrtoeol();
4778 return show_panner_legend;
4781 return FALSE;
4784 static void
4785 panner_h_cleanup(int from_y, int from_x, int to_x)
4787 if (!panner_legend(from_y))
4788 do_h_line(from_y, from_x, ' ', to_x);
4791 static void
4792 panner_v_cleanup(int from_y, int from_x, int to_y)
4794 if (!panner_legend(from_y))
4795 do_v_line(from_y, from_x, ' ', to_y);
4798 static void
4799 fill_pad(WINDOW *panpad, bool pan_lines)
4801 int y, x;
4802 unsigned gridcount = 0;
4804 wmove(panpad, 0, 0);
4805 for (y = 0; y < getmaxy(panpad); y++) {
4806 for (x = 0; x < getmaxx(panpad); x++) {
4807 if (y % GRIDSIZE == 0 && x % GRIDSIZE == 0) {
4808 if (y == 0 && x == 0)
4809 waddch(panpad, pan_lines ? ACS_ULCORNER : '+');
4810 else if (y == 0)
4811 waddch(panpad, pan_lines ? ACS_TTEE : '+');
4812 else if (y == 0 || x == 0)
4813 waddch(panpad, pan_lines ? ACS_LTEE : '+');
4814 else
4815 waddch(panpad, (chtype) ((pan_lines ? 'a' : 'A') +
4816 (int) (gridcount++ % 26)));
4817 } else if (y % GRIDSIZE == 0)
4818 waddch(panpad, pan_lines ? ACS_HLINE : '-');
4819 else if (x % GRIDSIZE == 0)
4820 waddch(panpad, pan_lines ? ACS_VLINE : '|');
4821 else
4822 waddch(panpad, ' ');
4827 static void
4828 panner(WINDOW *pad,
4829 int top_x, int top_y, int porty, int portx,
4830 int (*pgetc) (WINDOW *))
4832 #if HAVE_GETTIMEOFDAY
4833 struct timeval before, after;
4834 bool timing = TRUE;
4835 #endif
4836 bool pan_lines = FALSE;
4837 bool scrollers = TRUE;
4838 int basex = 0;
4839 int basey = 0;
4840 int pxmax, pymax, lowend, highend, c;
4842 getmaxyx(pad, pymax, pxmax);
4843 scrollok(stdscr, FALSE); /* we don't want stdscr to scroll! */
4845 c = KEY_REFRESH;
4846 do {
4847 #ifdef NCURSES_VERSION
4849 * During shell-out, the user may have resized the window. Adjust
4850 * the port size of the pad to accommodate this. Ncurses automatically
4851 * resizes all of the normal windows to fit on the new screen.
4853 if (top_x > COLS)
4854 top_x = COLS;
4855 if (portx > COLS)
4856 portx = COLS;
4857 if (top_y > LINES)
4858 top_y = LINES;
4859 if (porty > LINES)
4860 porty = LINES;
4861 #endif
4862 switch (c) {
4863 case KEY_REFRESH:
4864 erase();
4866 /* FALLTHRU */
4867 case '?':
4868 if (c == '?')
4869 show_panner_legend = !show_panner_legend;
4870 panner_legend(LINES - 4);
4871 panner_legend(LINES - 3);
4872 panner_legend(LINES - 2);
4873 panner_legend(LINES - 1);
4874 break;
4875 case 'a':
4876 pan_lines = !pan_lines;
4877 fill_pad(pad, pan_lines);
4878 pending_pan = FALSE;
4879 break;
4881 #if HAVE_GETTIMEOFDAY
4882 case 't':
4883 timing = !timing;
4884 if (!timing)
4885 panner_legend(LINES - 1);
4886 break;
4887 #endif
4888 case 's':
4889 scrollers = !scrollers;
4890 break;
4892 /* Move the top-left corner of the pad, keeping the bottom-right
4893 * corner fixed.
4895 case 'h': /* increase-columns: move left edge to left */
4896 if (top_x <= 0)
4897 beep();
4898 else {
4899 panner_v_cleanup(top_y, top_x, porty);
4900 top_x--;
4902 break;
4904 case 'j': /* decrease-lines: move top-edge down */
4905 if (top_y >= porty)
4906 beep();
4907 else {
4908 panner_h_cleanup(top_y - 1, top_x - (top_x > 0), portx);
4909 top_y++;
4911 break;
4913 case 'k': /* increase-lines: move top-edge up */
4914 if (top_y <= 0)
4915 beep();
4916 else {
4917 top_y--;
4918 panner_h_cleanup(top_y, top_x, portx);
4920 break;
4922 case 'l': /* decrease-columns: move left-edge to right */
4923 if (top_x >= portx)
4924 beep();
4925 else {
4926 panner_v_cleanup(top_y - (top_y > 0), top_x - 1, porty);
4927 top_x++;
4929 break;
4931 /* Move the bottom-right corner of the pad, keeping the top-left
4932 * corner fixed.
4934 case KEY_IC: /* increase-columns: move right-edge to right */
4935 if (portx >= pxmax || portx >= COLS)
4936 beep();
4937 else {
4938 panner_v_cleanup(top_y - (top_y > 0), portx - 1, porty);
4939 ++portx;
4941 break;
4943 case KEY_IL: /* increase-lines: move bottom-edge down */
4944 if (porty >= pymax || porty >= LINES)
4945 beep();
4946 else {
4947 panner_h_cleanup(porty - 1, top_x - (top_x > 0), portx);
4948 ++porty;
4950 break;
4952 case KEY_DC: /* decrease-columns: move bottom edge up */
4953 if (portx <= top_x)
4954 beep();
4955 else {
4956 portx--;
4957 panner_v_cleanup(top_y - (top_y > 0), portx, porty);
4959 break;
4961 case KEY_DL: /* decrease-lines */
4962 if (porty <= top_y)
4963 beep();
4964 else {
4965 porty--;
4966 panner_h_cleanup(porty, top_x - (top_x > 0), portx);
4968 break;
4970 case KEY_LEFT: /* pan leftwards */
4971 if (basex > 0)
4972 basex--;
4973 else
4974 beep();
4975 break;
4977 case KEY_RIGHT: /* pan rightwards */
4978 if (basex + portx - (pymax > porty) < pxmax)
4979 basex++;
4980 else
4981 beep();
4982 break;
4984 case KEY_UP: /* pan upwards */
4985 if (basey > 0)
4986 basey--;
4987 else
4988 beep();
4989 break;
4991 case KEY_DOWN: /* pan downwards */
4992 if (basey + porty - (pxmax > portx) < pymax)
4993 basey++;
4994 else
4995 beep();
4996 break;
4998 case 'H':
4999 case KEY_HOME:
5000 case KEY_FIND:
5001 basey = 0;
5002 break;
5004 case 'E':
5005 case KEY_END:
5006 case KEY_SELECT:
5007 basey = pymax - porty;
5008 if (basey < 0)
5009 basey = 0;
5010 break;
5012 default:
5013 beep();
5014 break;
5017 MvAddCh(top_y - 1, top_x - 1, ACS_ULCORNER);
5018 do_v_line(top_y, top_x - 1, ACS_VLINE, porty);
5019 do_h_line(top_y - 1, top_x, ACS_HLINE, portx);
5021 if (scrollers && (pxmax > portx - 1)) {
5022 int length = (portx - top_x - 1);
5023 float ratio = ((float) length) / ((float) pxmax);
5025 lowend = (int) ((float) top_x + ((float) basex * ratio));
5026 highend = (int) ((float) top_x + ((float) (basex + length) * ratio));
5028 do_h_line(porty - 1, top_x, ACS_HLINE, lowend);
5029 if (highend < portx) {
5030 attron(A_REVERSE);
5031 do_h_line(porty - 1, lowend, ' ', highend + 1);
5032 attroff(A_REVERSE);
5033 do_h_line(porty - 1, highend + 1, ACS_HLINE, portx);
5035 } else
5036 do_h_line(porty - 1, top_x, ACS_HLINE, portx);
5038 if (scrollers && (pymax > porty - 1)) {
5039 int length = (porty - top_y - 1);
5040 float ratio = ((float) length) / ((float) pymax);
5042 lowend = (int) ((float) top_y + ((float) basey * ratio));
5043 highend = (int) ((float) top_y + ((float) (basey + length) * ratio));
5045 do_v_line(top_y, portx - 1, ACS_VLINE, lowend);
5046 if (highend < porty) {
5047 attron(A_REVERSE);
5048 do_v_line(lowend, portx - 1, ' ', highend + 1);
5049 attroff(A_REVERSE);
5050 do_v_line(highend + 1, portx - 1, ACS_VLINE, porty);
5052 } else
5053 do_v_line(top_y, portx - 1, ACS_VLINE, porty);
5055 MvAddCh(top_y - 1, portx - 1, ACS_URCORNER);
5056 MvAddCh(porty - 1, top_x - 1, ACS_LLCORNER);
5057 MvAddCh(porty - 1, portx - 1, ACS_LRCORNER);
5059 if (!pending_pan) {
5060 #if HAVE_GETTIMEOFDAY
5061 gettimeofday(&before, 0);
5062 #endif
5063 wnoutrefresh(stdscr);
5065 pnoutrefresh(pad,
5066 basey, basex,
5067 top_y, top_x,
5068 porty - (pxmax > portx) - 1,
5069 portx - (pymax > porty) - 1);
5071 doupdate();
5072 #if HAVE_GETTIMEOFDAY
5073 #define TIMEVAL2S(data) ((double) data.tv_sec + ((double) data.tv_usec / 1.0e6))
5074 if (timing) {
5075 double elapsed;
5076 gettimeofday(&after, 0);
5077 elapsed = (TIMEVAL2S(after) - TIMEVAL2S(before));
5078 move(LINES - 1, COLS - 12);
5079 printw("Secs: %2.03f", elapsed);
5080 refresh();
5082 #endif
5085 } while
5086 ((c = pgetc(pad)) != KEY_EXIT);
5088 scrollok(stdscr, TRUE); /* reset to driver's default */
5091 static int
5092 padgetch(WINDOW *win)
5094 static int count;
5095 static int last;
5096 int c;
5098 if ((pending_pan = (count > 0)) != FALSE) {
5099 count--;
5100 pending_pan = (count != 0);
5101 } else {
5102 for (;;) {
5103 switch (c = wGetchar(win)) {
5104 case '!':
5105 ShellOut(FALSE);
5106 /* FALLTHRU */
5107 case CTRL('r'):
5108 endwin();
5109 refresh();
5110 c = KEY_REFRESH;
5111 break;
5112 case CTRL('l'):
5113 c = KEY_REFRESH;
5114 break;
5115 case 'U':
5116 c = KEY_UP;
5117 break;
5118 case 'D':
5119 c = KEY_DOWN;
5120 break;
5121 case 'R':
5122 c = KEY_RIGHT;
5123 break;
5124 case 'L':
5125 c = KEY_LEFT;
5126 break;
5127 case '+':
5128 c = KEY_IL;
5129 break;
5130 case '-':
5131 c = KEY_DL;
5132 break;
5133 case '>':
5134 c = KEY_IC;
5135 break;
5136 case '<':
5137 c = KEY_DC;
5138 break;
5139 case ERR: /* FALLTHRU */
5140 case case_QUIT:
5141 count = 0;
5142 c = KEY_EXIT;
5143 break;
5144 default:
5145 if (c >= '0' && c <= '9') {
5146 count = count * 10 + (c - '0');
5147 continue;
5149 break;
5151 last = c;
5152 break;
5154 if (count > 0)
5155 count--;
5157 return (last);
5160 #define PAD_HIGH 200
5161 #define PAD_WIDE 200
5163 static void
5164 demo_pad(void)
5165 /* Demonstrate pads. */
5167 WINDOW *panpad = newpad(PAD_HIGH, PAD_WIDE);
5169 if (panpad == 0) {
5170 Cannot("cannot create requested pad");
5171 return;
5174 fill_pad(panpad, FALSE);
5176 panner_legend(LINES - 4);
5177 panner_legend(LINES - 3);
5178 panner_legend(LINES - 2);
5179 panner_legend(LINES - 1);
5181 keypad(panpad, TRUE);
5183 /* Make the pad (initially) narrow enough that a trace file won't wrap.
5184 * We'll still be able to widen it during a test, since that's required
5185 * for testing boundaries.
5187 panner(panpad, 2, 2, LINES - 5, COLS - 15, padgetch);
5189 delwin(panpad);
5190 endwin();
5191 erase();
5194 /****************************************************************************
5196 * Tests from John Burnell's PDCurses tester
5198 ****************************************************************************/
5200 static void
5201 Continue(WINDOW *win)
5203 noecho();
5204 wmove(win, 10, 1);
5205 MvWAddStr(win, 10, 1, " Press any key to continue");
5206 wrefresh(win);
5207 wGetchar(win);
5210 static void
5211 flushinp_test(WINDOW *win)
5212 /* Input test, adapted from John Burnell's PDCurses tester */
5214 int w, h, bx, by, sw, sh, i;
5216 WINDOW *subWin;
5217 wclear(win);
5219 getmaxyx(win, h, w);
5220 getbegyx(win, by, bx);
5221 sw = w / 3;
5222 sh = h / 3;
5223 if ((subWin = subwin(win, sh, sw, by + h - sh - 2, bx + w - sw - 2)) == 0)
5224 return;
5226 #ifdef A_COLOR
5227 if (use_colors) {
5228 init_pair(2, COLOR_CYAN, COLOR_BLUE);
5229 wbkgd(subWin, COLOR_PAIR(2) | ' ');
5231 #endif
5232 (void) wattrset(subWin, A_BOLD);
5233 box(subWin, ACS_VLINE, ACS_HLINE);
5234 MvWAddStr(subWin, 2, 1, "This is a subwindow");
5235 wrefresh(win);
5238 * This used to set 'nocbreak()'. However, Alexander Lukyanov says that
5239 * it only happened to "work" on SVr4 because that implementation does not
5240 * emulate nocbreak+noecho mode, whereas ncurses does. To get the desired
5241 * test behavior, we're using 'cbreak()', which will allow a single
5242 * character to return without needing a newline. - T.Dickey 1997/10/11.
5244 cbreak();
5245 MvWAddStr(win, 0, 1, "This is a test of the flushinp() call.");
5247 MvWAddStr(win, 2, 1, "Type random keys for 5 seconds.");
5248 MvWAddStr(win, 3, 1,
5249 "These should be discarded (not echoed) after the subwindow goes away.");
5250 wrefresh(win);
5252 for (i = 0; i < 5; i++) {
5253 MvWPrintw(subWin, 1, 1, "Time = %d", i);
5254 wrefresh(subWin);
5255 napms(1000);
5256 flushinp();
5259 delwin(subWin);
5260 werase(win);
5261 flash();
5262 wrefresh(win);
5263 napms(1000);
5265 MvWAddStr(win, 2, 1,
5266 "If you were still typing when the window timer expired,");
5267 MvWAddStr(win, 3, 1,
5268 "or else you typed nothing at all while it was running,");
5269 MvWAddStr(win, 4, 1,
5270 "test was invalid. You'll see garbage or nothing at all. ");
5271 MvWAddStr(win, 6, 1, "Press a key");
5272 wmove(win, 9, 10);
5273 wrefresh(win);
5274 echo();
5275 wGetchar(win);
5276 flushinp();
5277 MvWAddStr(win, 12, 0,
5278 "If you see any key other than what you typed, flushinp() is broken.");
5279 Continue(win);
5281 wmove(win, 9, 10);
5282 wdelch(win);
5283 wrefresh(win);
5284 wmove(win, 12, 0);
5285 clrtoeol();
5286 waddstr(win,
5287 "What you typed should now have been deleted; if not, wdelch() failed.");
5288 Continue(win);
5290 cbreak();
5293 /****************************************************************************
5295 * Menu test
5297 ****************************************************************************/
5299 #if USE_LIBMENU
5301 #define MENU_Y 8
5302 #define MENU_X 8
5304 static int
5305 menu_virtualize(int c)
5307 if (c == '\n' || c == KEY_EXIT)
5308 return (MAX_COMMAND + 1);
5309 else if (c == 'u')
5310 return (REQ_SCR_ULINE);
5311 else if (c == 'd')
5312 return (REQ_SCR_DLINE);
5313 else if (c == 'b' || c == KEY_NPAGE)
5314 return (REQ_SCR_UPAGE);
5315 else if (c == 'f' || c == KEY_PPAGE)
5316 return (REQ_SCR_DPAGE);
5317 else if (c == 'n' || c == KEY_DOWN)
5318 return (REQ_NEXT_ITEM);
5319 else if (c == 'p' || c == KEY_UP)
5320 return (REQ_PREV_ITEM);
5321 else if (c == ' ')
5322 return (REQ_TOGGLE_ITEM);
5323 else {
5324 if (c != KEY_MOUSE)
5325 beep();
5326 return (c);
5330 static CONST_MENUS char *animals[] =
5332 "Lions",
5333 "Tigers",
5334 "Bears",
5335 "(Oh my!)",
5336 "Newts",
5337 "Platypi",
5338 "Lemurs",
5339 "(Oh really?!)",
5340 "Leopards",
5341 "Panthers",
5342 "Pumas",
5343 "Lions, Tigers, Bears, (Oh my!), Newts, Platypi, Lemurs",
5344 "Lions, Tigers, Bears, (Oh my!), Newts, Platypi, Lemurs, Lions, Tigers, Bears, (Oh my!), Newts, Platypi, Lemurs",
5345 (char *) 0
5348 static void
5349 menu_test(void)
5351 MENU *m;
5352 ITEM *items[SIZEOF(animals)];
5353 ITEM **ip = items;
5354 CONST_MENUS char **ap;
5355 int mrows, mcols, c;
5356 WINDOW *menuwin;
5358 #ifdef NCURSES_MOUSE_VERSION
5359 mousemask(ALL_MOUSE_EVENTS, (mmask_t *) 0);
5360 #endif
5361 MvAddStr(0, 0, "This is the menu test:");
5362 MvAddStr(2, 0, " Use up and down arrow to move the select bar.");
5363 MvAddStr(3, 0, " 'n' and 'p' act like arrows.");
5364 MvAddStr(4, 0,
5365 " 'b' and 'f' scroll up/down (page), 'u' and 'd' (line).");
5366 MvAddStr(5, 0, " Press return to exit.");
5367 refresh();
5369 for (ap = animals; *ap; ap++) {
5370 if ((*ip = new_item(*ap, "")) != 0)
5371 ++ip;
5373 *ip = (ITEM *) 0;
5375 m = new_menu(items);
5377 set_menu_format(m, (SIZEOF(animals) + 1) / 2, 1);
5378 scale_menu(m, &mrows, &mcols);
5380 menuwin = newwin(mrows + 2, mcols + 2, MENU_Y, MENU_X);
5381 set_menu_win(m, menuwin);
5382 keypad(menuwin, TRUE);
5383 box(menuwin, 0, 0);
5385 set_menu_sub(m, derwin(menuwin, mrows, mcols, 1, 1));
5387 post_menu(m);
5389 while ((c = menu_driver(m, menu_virtualize(wGetchar(menuwin)))) != E_UNKNOWN_COMMAND) {
5390 if (c == E_NOT_POSTED)
5391 break;
5392 if (c == E_REQUEST_DENIED)
5393 beep();
5394 continue;
5397 MvPrintw(LINES - 2, 0,
5398 "You chose: %s\n", item_name(current_item(m)));
5399 (void) addstr("Press any key to continue...");
5400 wGetchar(stdscr);
5402 unpost_menu(m);
5403 delwin(menuwin);
5405 free_menu(m);
5406 for (ip = items; *ip; ip++)
5407 free_item(*ip);
5408 #ifdef NCURSES_MOUSE_VERSION
5409 mousemask(0, (mmask_t *) 0);
5410 #endif
5413 #ifdef TRACE
5414 #define T_TBL(name) { #name, name }
5415 static struct {
5416 const char *name;
5417 unsigned mask;
5418 } t_tbl[] = {
5420 T_TBL(TRACE_DISABLE),
5421 T_TBL(TRACE_TIMES),
5422 T_TBL(TRACE_TPUTS),
5423 T_TBL(TRACE_UPDATE),
5424 T_TBL(TRACE_MOVE),
5425 T_TBL(TRACE_CHARPUT),
5426 T_TBL(TRACE_ORDINARY),
5427 T_TBL(TRACE_CALLS),
5428 T_TBL(TRACE_VIRTPUT),
5429 T_TBL(TRACE_IEVENT),
5430 T_TBL(TRACE_BITS),
5431 T_TBL(TRACE_ICALLS),
5432 T_TBL(TRACE_CCALLS),
5433 T_TBL(TRACE_DATABASE),
5434 T_TBL(TRACE_ATTRS),
5435 T_TBL(TRACE_MAXIMUM),
5437 (char *) 0, 0
5441 static char *
5442 tracetrace(unsigned tlevel)
5444 static char *buf;
5445 int n;
5447 if (buf == 0) {
5448 size_t need = 12;
5449 for (n = 0; t_tbl[n].name != 0; n++)
5450 need += strlen(t_tbl[n].name) + 2;
5451 buf = typeMalloc(char, need);
5453 sprintf(buf, "0x%02x = {", tlevel);
5454 if (tlevel == 0) {
5455 sprintf(buf + strlen(buf), "%s, ", t_tbl[0].name);
5456 } else {
5457 for (n = 1; t_tbl[n].name != 0; n++)
5458 if ((tlevel & t_tbl[n].mask) == t_tbl[n].mask) {
5459 strcat(buf, t_tbl[n].name);
5460 strcat(buf, ", ");
5463 if (buf[strlen(buf) - 2] == ',')
5464 buf[strlen(buf) - 2] = '\0';
5465 return (strcat(buf, "}"));
5468 /* fake a dynamically reconfigurable menu using the 0th entry to deselect
5469 * the others
5471 static int
5472 run_trace_menu(MENU * m)
5474 ITEM **items;
5475 ITEM *i, **p;
5477 for (;;) {
5478 bool changed = FALSE;
5479 switch (menu_driver(m, menu_virtualize(wGetchar(menu_win(m))))) {
5480 case E_UNKNOWN_COMMAND:
5481 return FALSE;
5482 default:
5483 items = menu_items(m);
5484 i = current_item(m);
5485 if (i == items[0]) {
5486 if (item_value(i)) {
5487 for (p = items + 1; *p != 0; p++)
5488 if (item_value(*p)) {
5489 set_item_value(*p, FALSE);
5490 changed = TRUE;
5493 } else {
5494 for (p = items + 1; *p != 0; p++)
5495 if (item_value(*p)) {
5496 set_item_value(items[0], FALSE);
5497 changed = TRUE;
5498 break;
5501 if (!changed)
5502 return TRUE;
5507 static void
5508 trace_set(void)
5509 /* interactively set the trace level */
5511 MENU *m;
5512 ITEM *items[SIZEOF(t_tbl)];
5513 ITEM **ip = items;
5514 int mrows, mcols;
5515 unsigned newtrace;
5516 int n;
5517 WINDOW *menuwin;
5519 MvAddStr(0, 0, "Interactively set trace level:");
5520 MvAddStr(2, 0, " Press space bar to toggle a selection.");
5521 MvAddStr(3, 0, " Use up and down arrow to move the select bar.");
5522 MvAddStr(4, 0, " Press return to set the trace level.");
5523 MvPrintw(6, 0, "(Current trace level is %s)", tracetrace(_nc_tracing));
5525 refresh();
5527 for (n = 0; t_tbl[n].name != 0; n++) {
5528 if ((*ip = new_item(t_tbl[n].name, "")) != 0) {
5529 ++ip;
5532 *ip = (ITEM *) 0;
5534 m = new_menu(items);
5536 set_menu_format(m, 0, 2);
5537 scale_menu(m, &mrows, &mcols);
5539 menu_opts_off(m, O_ONEVALUE);
5540 menuwin = newwin(mrows + 2, mcols + 2, MENU_Y, MENU_X);
5541 set_menu_win(m, menuwin);
5542 keypad(menuwin, TRUE);
5543 box(menuwin, 0, 0);
5545 set_menu_sub(m, derwin(menuwin, mrows, mcols, 1, 1));
5547 post_menu(m);
5549 for (ip = menu_items(m); *ip; ip++) {
5550 unsigned mask = t_tbl[item_index(*ip)].mask;
5551 if (mask == 0)
5552 set_item_value(*ip, _nc_tracing == 0);
5553 else if ((mask & _nc_tracing) == mask)
5554 set_item_value(*ip, TRUE);
5557 while (run_trace_menu(m))
5558 continue;
5560 newtrace = 0;
5561 for (ip = menu_items(m); *ip; ip++)
5562 if (item_value(*ip))
5563 newtrace |= t_tbl[item_index(*ip)].mask;
5564 trace(newtrace);
5565 Trace(("trace level interactively set to %s", tracetrace(_nc_tracing)));
5567 MvPrintw(LINES - 2, 0,
5568 "Trace level is %s\n", tracetrace(_nc_tracing));
5569 (void) addstr("Press any key to continue...");
5570 wGetchar(stdscr);
5572 unpost_menu(m);
5573 delwin(menuwin);
5575 free_menu(m);
5576 for (ip = items; *ip; ip++)
5577 free_item(*ip);
5579 #endif /* TRACE */
5580 #endif /* USE_LIBMENU */
5582 /****************************************************************************
5584 * Forms test
5586 ****************************************************************************/
5587 #if USE_LIBFORM
5588 static FIELD *
5589 make_label(int frow, int fcol, NCURSES_CONST char *label)
5591 FIELD *f = new_field(1, (int) strlen(label), frow, fcol, 0, 0);
5593 if (f) {
5594 set_field_buffer(f, 0, label);
5595 set_field_opts(f, (int) ((unsigned) field_opts(f) & ~O_ACTIVE));
5597 return (f);
5600 static FIELD *
5601 make_field(int frow, int fcol, int rows, int cols, bool secure)
5603 FIELD *f = new_field(rows, cols, frow, fcol, 0, secure ? 1 : 0);
5605 if (f) {
5606 set_field_back(f, A_UNDERLINE);
5607 set_field_userptr(f, (void *) 0);
5609 return (f);
5612 static void
5613 display_form(FORM * f)
5615 WINDOW *w;
5616 int rows, cols;
5618 scale_form(f, &rows, &cols);
5620 if ((w = newwin(rows + 2, cols + 4, 0, 0)) != (WINDOW *) 0) {
5621 set_form_win(f, w);
5622 set_form_sub(f, derwin(w, rows, cols, 1, 2));
5623 box(w, 0, 0);
5624 keypad(w, TRUE);
5627 if (post_form(f) != E_OK)
5628 wrefresh(w);
5631 static void
5632 erase_form(FORM * f)
5634 WINDOW *w = form_win(f);
5635 WINDOW *s = form_sub(f);
5637 unpost_form(f);
5638 werase(w);
5639 wrefresh(w);
5640 delwin(s);
5641 delwin(w);
5644 static int
5645 edit_secure(FIELD * me, int c)
5647 int rows, cols, frow, fcol, nrow, nbuf;
5649 if (field_info(me, &rows, &cols, &frow, &fcol, &nrow, &nbuf) == E_OK
5650 && nbuf > 0) {
5651 char *source = field_buffer(me, 1);
5652 char temp[80];
5653 long len;
5655 strcpy(temp, source ? source : "");
5656 len = (long) (char *) field_userptr(me);
5657 if (c <= KEY_MAX) {
5658 if (isgraph(c) && (len + 1) < (int) sizeof(temp)) {
5659 temp[len++] = (char) c;
5660 temp[len] = 0;
5661 set_field_buffer(me, 1, temp);
5662 c = '*';
5663 } else {
5664 c = 0;
5666 } else {
5667 switch (c) {
5668 case REQ_BEG_FIELD:
5669 case REQ_CLR_EOF:
5670 case REQ_CLR_EOL:
5671 case REQ_DEL_LINE:
5672 case REQ_DEL_WORD:
5673 case REQ_DOWN_CHAR:
5674 case REQ_END_FIELD:
5675 case REQ_INS_CHAR:
5676 case REQ_INS_LINE:
5677 case REQ_LEFT_CHAR:
5678 case REQ_NEW_LINE:
5679 case REQ_NEXT_WORD:
5680 case REQ_PREV_WORD:
5681 case REQ_RIGHT_CHAR:
5682 case REQ_UP_CHAR:
5683 c = 0; /* we don't want to do inline editing */
5684 break;
5685 case REQ_CLR_FIELD:
5686 if (len) {
5687 temp[0] = 0;
5688 set_field_buffer(me, 1, temp);
5690 break;
5691 case REQ_DEL_CHAR:
5692 case REQ_DEL_PREV:
5693 if (len) {
5694 temp[--len] = 0;
5695 set_field_buffer(me, 1, temp);
5697 break;
5700 set_field_userptr(me, (void *) len);
5702 return c;
5705 static int
5706 form_virtualize(FORM * f, WINDOW *w)
5708 /* *INDENT-OFF* */
5709 static const struct {
5710 int code;
5711 int result;
5712 } lookup[] = {
5713 { CTRL('A'), REQ_NEXT_CHOICE },
5714 { CTRL('B'), REQ_PREV_WORD },
5715 { CTRL('C'), REQ_CLR_EOL },
5716 { CTRL('D'), REQ_DOWN_FIELD },
5717 { CTRL('E'), REQ_END_FIELD },
5718 { CTRL('F'), REQ_NEXT_PAGE },
5719 { CTRL('G'), REQ_DEL_WORD },
5720 { CTRL('H'), REQ_DEL_PREV },
5721 { CTRL('I'), REQ_INS_CHAR },
5722 { CTRL('K'), REQ_CLR_EOF },
5723 { CTRL('L'), REQ_LEFT_FIELD },
5724 { CTRL('M'), REQ_NEW_LINE },
5725 { CTRL('N'), REQ_NEXT_FIELD },
5726 { CTRL('O'), REQ_INS_LINE },
5727 { CTRL('P'), REQ_PREV_FIELD },
5728 { CTRL('R'), REQ_RIGHT_FIELD },
5729 { CTRL('S'), REQ_BEG_FIELD },
5730 { CTRL('U'), REQ_UP_FIELD },
5731 { CTRL('V'), REQ_DEL_CHAR },
5732 { CTRL('W'), REQ_NEXT_WORD },
5733 { CTRL('X'), REQ_CLR_FIELD },
5734 { CTRL('Y'), REQ_DEL_LINE },
5735 { CTRL('Z'), REQ_PREV_CHOICE },
5736 { ESCAPE, MAX_FORM_COMMAND + 1 },
5737 { KEY_BACKSPACE, REQ_DEL_PREV },
5738 { KEY_DOWN, REQ_DOWN_CHAR },
5739 { KEY_END, REQ_LAST_FIELD },
5740 { KEY_HOME, REQ_FIRST_FIELD },
5741 { KEY_LEFT, REQ_LEFT_CHAR },
5742 { KEY_LL, REQ_LAST_FIELD },
5743 { KEY_NEXT, REQ_NEXT_FIELD },
5744 { KEY_NPAGE, REQ_NEXT_PAGE },
5745 { KEY_PPAGE, REQ_PREV_PAGE },
5746 { KEY_PREVIOUS, REQ_PREV_FIELD },
5747 { KEY_RIGHT, REQ_RIGHT_CHAR },
5748 { KEY_UP, REQ_UP_CHAR },
5749 { QUIT, MAX_FORM_COMMAND + 1 }
5751 /* *INDENT-ON* */
5753 static int mode = REQ_INS_MODE;
5754 int c = wGetchar(w);
5755 unsigned n;
5756 FIELD *me = current_field(f);
5757 bool current = TRUE;
5759 if (c == CTRL(']')) {
5760 if (mode == REQ_INS_MODE) {
5761 mode = REQ_OVL_MODE;
5762 } else {
5763 mode = REQ_INS_MODE;
5765 c = mode;
5766 } else {
5767 for (n = 0; n < SIZEOF(lookup); n++) {
5768 if (lookup[n].code == c) {
5769 c = lookup[n].result;
5770 break;
5774 MvPrintw(0, COLS - 6, "(%s)", mode == REQ_INS_MODE ? "INS" : "OVL");
5777 * Force the field that the user is typing into to be in reverse video,
5778 * while the other fields are shown underlined.
5780 switch (c) {
5781 case REQ_BEG_FIELD:
5782 case REQ_CLR_EOF:
5783 case REQ_CLR_EOL:
5784 case REQ_CLR_FIELD:
5785 case REQ_DEL_CHAR:
5786 case REQ_DEL_LINE:
5787 case REQ_DEL_PREV:
5788 case REQ_DEL_WORD:
5789 case REQ_END_FIELD:
5790 case REQ_INS_CHAR:
5791 case REQ_INS_LINE:
5792 case REQ_LEFT_CHAR:
5793 case REQ_LEFT_FIELD:
5794 case REQ_NEXT_WORD:
5795 case REQ_RIGHT_CHAR:
5796 current = TRUE;
5797 break;
5798 default:
5799 current = (c < KEY_MAX);
5800 break;
5802 if (current) {
5803 c = edit_secure(me, c);
5804 set_field_back(me, A_REVERSE);
5805 } else {
5806 c = edit_secure(me, c);
5807 set_field_back(me, A_UNDERLINE);
5809 return c;
5812 static int
5813 my_form_driver(FORM * form, int c)
5815 if (c == (MAX_FORM_COMMAND + 1)
5816 && form_driver(form, REQ_VALIDATION) == E_OK)
5817 return (TRUE);
5818 else {
5819 beep();
5820 return (FALSE);
5824 #ifdef NCURSES_VERSION
5825 #define FIELDCHECK_CB(func) bool func(FIELD * fld, const void * data GCC_UNUSED)
5826 #define CHAR_CHECK_CB(func) bool func(int ch, const void *data GCC_UNUSED)
5827 #else
5828 #define FIELDCHECK_CB(func) int func(FIELD * fld, char * data GCC_UNUSED)
5829 #define CHAR_CHECK_CB(func) int func(int ch, char *data GCC_UNUSED)
5830 #endif
5833 * Allow a middle initial, optionally with a '.' to end it.
5835 static
5836 FIELDCHECK_CB(mi_field_check)
5838 char *s = field_buffer(fld, 0);
5839 int state = 0;
5840 int n;
5842 for (n = 0; s[n] != '\0'; ++n) {
5843 switch (state) {
5844 case 0:
5845 if (s[n] == '.') {
5846 if (n != 1)
5847 return FALSE;
5848 state = 2;
5849 } else if (isspace(UChar(s[n]))) {
5850 state = 2;
5852 break;
5853 case 2:
5854 if (!isspace(UChar(s[n])))
5855 return FALSE;
5856 break;
5860 /* force the form to display a leading capital */
5861 if (islower(UChar(s[0]))) {
5862 s[0] = (char) toupper(UChar(s[0]));
5863 set_field_buffer(fld, 0, s);
5865 return TRUE;
5868 static
5869 CHAR_CHECK_CB(mi_char_check)
5871 return ((isalpha(ch) || ch == '.') ? TRUE : FALSE);
5875 * Passwords should be at least 6 characters.
5877 static
5878 FIELDCHECK_CB(pw_field_check)
5880 char *s = field_buffer(fld, 0);
5881 int n;
5883 for (n = 0; s[n] != '\0'; ++n) {
5884 if (isspace(UChar(s[n]))) {
5885 if (n < 6)
5886 return FALSE;
5889 return TRUE;
5892 static
5893 CHAR_CHECK_CB(pw_char_check)
5895 return (isgraph(ch) ? TRUE : FALSE);
5898 static void
5899 demo_forms(void)
5901 WINDOW *w;
5902 FORM *form;
5903 FIELD *f[12], *secure;
5904 FIELDTYPE *fty_middle = new_fieldtype(mi_field_check, mi_char_check);
5905 FIELDTYPE *fty_passwd = new_fieldtype(pw_field_check, pw_char_check);
5906 int finished = 0, c;
5907 unsigned n = 0;
5909 #ifdef NCURSES_MOUSE_VERSION
5910 mousemask(ALL_MOUSE_EVENTS, (mmask_t *) 0);
5911 #endif
5913 move(18, 0);
5914 addstr("Defined edit/traversal keys: ^Q/ESC- exit form\n");
5915 addstr("^N -- go to next field ^P -- go to previous field\n");
5916 addstr("Home -- go to first field End -- go to last field\n");
5917 addstr("^L -- go to field to left ^R -- go to field to right\n");
5918 addstr("^U -- move upward to field ^D -- move downward to field\n");
5919 addstr("^W -- go to next word ^B -- go to previous word\n");
5920 addstr("^S -- go to start of field ^E -- go to end of field\n");
5921 addstr("^H -- delete previous char ^Y -- delete line\n");
5922 addstr("^G -- delete current word ^C -- clear to end of line\n");
5923 addstr("^K -- clear to end of field ^X -- clear field\n");
5924 addstr("Arrow keys move within a field as you would expect. ^] toggles overlay mode.");
5926 MvAddStr(4, 57, "Forms Entry Test");
5928 refresh();
5930 /* describe the form */
5931 memset(f, 0, sizeof(f));
5932 f[n++] = make_label(0, 15, "Sample Form");
5934 f[n++] = make_label(2, 0, "Last Name");
5935 f[n++] = make_field(3, 0, 1, 18, FALSE);
5936 set_field_type(f[n - 1], TYPE_ALPHA, 1);
5938 f[n++] = make_label(2, 20, "First Name");
5939 f[n++] = make_field(3, 20, 1, 12, FALSE);
5940 set_field_type(f[n - 1], TYPE_ALPHA, 1);
5942 f[n++] = make_label(2, 34, "Middle Name");
5943 f[n++] = make_field(3, 34, 1, 12, FALSE);
5944 set_field_type(f[n - 1], fty_middle);
5946 f[n++] = make_label(5, 0, "Comments");
5947 f[n++] = make_field(6, 0, 4, 46, FALSE);
5949 f[n++] = make_label(5, 20, "Password:");
5950 secure =
5951 f[n++] = make_field(5, 30, 1, 9, TRUE);
5952 set_field_type(f[n - 1], fty_passwd);
5953 f[n] = (FIELD *) 0;
5955 if ((form = new_form(f)) != 0) {
5957 display_form(form);
5959 w = form_win(form);
5960 raw();
5961 nonl(); /* lets us read ^M's */
5962 while (!finished) {
5963 switch (form_driver(form, c = form_virtualize(form, w))) {
5964 case E_OK:
5965 MvAddStr(5, 57, field_buffer(secure, 1));
5966 clrtoeol();
5967 refresh();
5968 break;
5969 case E_UNKNOWN_COMMAND:
5970 finished = my_form_driver(form, c);
5971 break;
5972 default:
5973 beep();
5974 break;
5978 erase_form(form);
5980 free_form(form);
5982 for (c = 0; f[c] != 0; c++)
5983 free_field(f[c]);
5984 free_fieldtype(fty_middle);
5985 free_fieldtype(fty_passwd);
5986 noraw();
5987 nl();
5989 #ifdef NCURSES_MOUSE_VERSION
5990 mousemask(ALL_MOUSE_EVENTS, (mmask_t *) 0);
5991 #endif
5993 #endif /* USE_LIBFORM */
5995 /****************************************************************************
5997 * Overlap test
5999 ****************************************************************************/
6001 static void
6002 fillwin(WINDOW *win, char ch)
6004 int y, x;
6005 int y1, x1;
6007 getmaxyx(win, y1, x1);
6008 for (y = 0; y < y1; y++) {
6009 wmove(win, y, 0);
6010 for (x = 0; x < x1; x++)
6011 waddch(win, UChar(ch));
6015 static void
6016 crosswin(WINDOW *win, char ch)
6018 int y, x;
6019 int y1, x1;
6021 getmaxyx(win, y1, x1);
6022 for (y = 0; y < y1; y++) {
6023 for (x = 0; x < x1; x++)
6024 if (((x > (x1 - 1) / 3) && (x <= (2 * (x1 - 1)) / 3))
6025 || (((y > (y1 - 1) / 3) && (y <= (2 * (y1 - 1)) / 3)))) {
6026 wmove(win, y, x);
6027 waddch(win, UChar(ch));
6032 #define OVERLAP_FLAVORS 5
6034 static void
6035 overlap_helpitem(int state, int item, char *message)
6037 int row = (item / 2);
6038 int col = ((item % 2) ? COLS / 2 : 0);
6040 move(LINES - 6 + row, col);
6041 printw("%c%c = %s", state == row ? '>' : ' ', 'a' + item, message);
6042 clrtoeol();
6045 static void
6046 overlap_test_1_attr(WINDOW *win, int flavor, int col)
6048 short cpair = (short) (1 + (flavor * 2) + col);
6050 switch (flavor) {
6051 case 0:
6052 (void) wattrset(win, A_NORMAL);
6053 break;
6054 case 1:
6055 (void) wattrset(win, A_BOLD);
6056 break;
6057 case 2:
6058 init_pair(cpair, COLOR_BLUE, COLOR_WHITE);
6059 (void) wattrset(win, (attr_t) COLOR_PAIR(cpair) | A_NORMAL);
6060 break;
6061 case 3:
6062 init_pair(cpair, COLOR_WHITE, COLOR_BLUE);
6063 (void) wattrset(win, (attr_t) COLOR_PAIR(cpair) | A_BOLD);
6064 break;
6068 static void
6069 overlap_test_2_attr(WINDOW *win, int flavor, int col)
6071 short cpair = (short) (9 + (flavor * 2) + col);
6073 switch (flavor) {
6074 case 0:
6075 /* no effect */
6076 break;
6077 case 1:
6078 /* no effect */
6079 break;
6080 case 2:
6081 init_pair(cpair, COLOR_RED, COLOR_GREEN);
6082 wbkgdset(win, colored_chtype(' ', A_BLINK, cpair));
6083 break;
6084 case 3:
6085 wbkgdset(win, ' ' | A_NORMAL);
6086 break;
6090 static int
6091 overlap_help(int state, int flavors[OVERLAP_FLAVORS])
6093 int row;
6094 int col;
6095 int item;
6096 const char *ths, *tht;
6097 char msg[80];
6099 if (state < 0)
6100 state += OVERLAP_FLAVORS;
6101 state = state % OVERLAP_FLAVORS;
6102 assert(state >= 0 && state < OVERLAP_FLAVORS);
6104 for (item = 0; item < (2 * OVERLAP_FLAVORS); ++item) {
6105 row = item / 2;
6106 col = item % 2;
6107 ths = col ? "B" : "A";
6108 tht = col ? "A" : "B";
6110 switch (row) {
6111 case 0:
6112 flavors[row] = 0;
6113 sprintf(msg, "refresh %s, then %s, then doupdate.", ths, tht);
6114 break;
6115 case 1:
6116 if (use_colors) {
6117 flavors[row] %= 4;
6118 } else {
6119 flavors[row] %= 2;
6121 overlap_test_1_attr(stdscr, flavors[row], col);
6122 sprintf(msg, "fill window %s with letter %s.", ths, ths);
6123 break;
6124 case 2:
6125 if (use_colors) {
6126 flavors[row] %= 4;
6127 } else {
6128 flavors[row] %= 2;
6130 switch (flavors[row]) {
6131 case 0:
6132 sprintf(msg, "cross pattern in window %s.", ths);
6133 break;
6134 case 1:
6135 sprintf(msg, "draw box in window %s.", ths);
6136 break;
6137 case 2:
6138 sprintf(msg, "set background of window %s.", ths);
6139 break;
6140 case 3:
6141 sprintf(msg, "reset background of window %s.", ths);
6142 break;
6144 break;
6145 case 3:
6146 flavors[row] = 0;
6147 sprintf(msg, "clear window %s.", ths);
6148 break;
6149 case 4:
6150 flavors[row] %= 4;
6151 switch (flavors[row]) {
6152 case 0:
6153 sprintf(msg, "overwrite %s onto %s.", ths, tht);
6154 break;
6155 case 1:
6156 sprintf(msg, "copywin(FALSE) %s onto %s.", ths, tht);
6157 break;
6158 case 2:
6159 sprintf(msg, "copywin(TRUE) %s onto %s.", ths, tht);
6160 break;
6161 case 3:
6162 sprintf(msg, "overlay %s onto %s.", ths, tht);
6163 break;
6165 break;
6167 overlap_helpitem(state, item, msg);
6168 (void) wattrset(stdscr, A_NORMAL);
6169 wbkgdset(stdscr, ' ' | A_NORMAL);
6171 move(LINES - 1, 0);
6172 printw("^Q/ESC = terminate test. Up/down/space select test variations (%d %d).",
6173 state, flavors[state]);
6175 return state;
6178 static void
6179 overlap_test_0(WINDOW *a, WINDOW *b)
6181 touchwin(a);
6182 touchwin(b);
6183 wnoutrefresh(a);
6184 wnoutrefresh(b);
6185 doupdate();
6188 static void
6189 overlap_test_1(int flavor, int col, WINDOW *a, char fill)
6191 overlap_test_1_attr(a, flavor, col);
6192 fillwin(a, fill);
6193 (void) wattrset(a, A_NORMAL);
6196 static void
6197 overlap_test_2(int flavor, int col, WINDOW *a, char fill)
6199 overlap_test_2_attr(a, flavor, col);
6200 switch (flavor) {
6201 case 0:
6202 crosswin(a, fill);
6203 break;
6204 case 1:
6205 box(a, 0, 0);
6206 break;
6207 case 2:
6208 /* done in overlap_test_2_attr */
6209 break;
6210 case 3:
6211 /* done in overlap_test_2_attr */
6212 break;
6216 static void
6217 overlap_test_3(WINDOW *a)
6219 wclear(a);
6220 wmove(a, 0, 0);
6223 static void
6224 overlap_test_4(int flavor, WINDOW *a, WINDOW *b)
6226 switch (flavor) {
6227 case 0:
6228 overwrite(a, b);
6229 break;
6230 case 1:
6231 copywin(a, b, 0, 0, 0, 0, getmaxy(b), getmaxx(b), FALSE);
6232 break;
6233 case 2:
6234 copywin(a, b, 0, 0, 0, 0, getmaxy(b), getmaxx(b), TRUE);
6235 break;
6236 case 3:
6237 overlay(a, b);
6238 break;
6242 /* test effects of overlapping windows */
6243 static void
6244 overlap_test(void)
6246 int ch;
6247 int state, flavor[OVERLAP_FLAVORS];
6249 WINDOW *win1 = newwin(9, 20, 3, 3);
6250 WINDOW *win2 = newwin(9, 20, 9, 16);
6252 curs_set(0);
6253 raw();
6254 refresh();
6255 move(0, 0);
6256 printw("This test shows the behavior of wnoutrefresh() with respect to\n");
6257 printw("the shared region of two overlapping windows A and B. The cross\n");
6258 printw("pattern in each window does not overlap the other.\n");
6260 memset(flavor, 0, sizeof(flavor));
6261 state = overlap_help(0, flavor);
6263 while (!isQuit(ch = Getchar()))
6264 switch (ch) {
6265 case 'a': /* refresh window A first, then B */
6266 overlap_test_0(win1, win2);
6267 break;
6269 case 'b': /* refresh window B first, then A */
6270 overlap_test_0(win2, win1);
6271 break;
6273 case 'c': /* fill window A so it's visible */
6274 overlap_test_1(flavor[1], 0, win1, 'A');
6275 break;
6277 case 'd': /* fill window B so it's visible */
6278 overlap_test_1(flavor[1], 1, win2, 'B');
6279 break;
6281 case 'e': /* cross test pattern in window A */
6282 overlap_test_2(flavor[2], 0, win1, 'A');
6283 break;
6285 case 'f': /* cross test pattern in window A */
6286 overlap_test_2(flavor[2], 1, win2, 'B');
6287 break;
6289 case 'g': /* clear window A */
6290 overlap_test_3(win1);
6291 break;
6293 case 'h': /* clear window B */
6294 overlap_test_3(win2);
6295 break;
6297 case 'i': /* overwrite A onto B */
6298 overlap_test_4(flavor[4], win1, win2);
6299 break;
6301 case 'j': /* overwrite B onto A */
6302 overlap_test_4(flavor[4], win2, win1);
6303 break;
6305 case CTRL('n'):
6306 case KEY_DOWN:
6307 state = overlap_help(state + 1, flavor);
6308 break;
6310 case CTRL('p'):
6311 case KEY_UP:
6312 state = overlap_help(state - 1, flavor);
6313 break;
6315 case ' ':
6316 flavor[state] += 1;
6317 state = overlap_help(state, flavor);
6318 break;
6320 case '?':
6321 state = overlap_help(state, flavor);
6322 break;
6324 default:
6325 beep();
6326 break;
6329 delwin(win2);
6330 delwin(win1);
6331 erase();
6332 curs_set(1);
6333 endwin();
6336 /****************************************************************************
6338 * Main sequence
6340 ****************************************************************************/
6342 static bool
6343 do_single_test(const char c)
6344 /* perform a single specified test */
6346 switch (c) {
6347 case 'a':
6348 getch_test();
6349 break;
6351 #if USE_WIDEC_SUPPORT
6352 case 'A':
6353 get_wch_test();
6354 break;
6355 #endif
6357 case 'b':
6358 attr_test();
6359 break;
6361 #if USE_WIDEC_SUPPORT
6362 case 'B':
6363 wide_attr_test();
6364 break;
6365 #endif
6367 case 'c':
6368 if (!use_colors)
6369 Cannot("does not support color.");
6370 else
6371 color_test();
6372 break;
6374 #if USE_WIDEC_SUPPORT
6375 case 'C':
6376 if (!use_colors)
6377 Cannot("does not support color.");
6378 else
6379 wide_color_test();
6380 break;
6381 #endif
6383 case 'd':
6384 if (!use_colors)
6385 Cannot("does not support color.");
6386 else if (!can_change_color())
6387 Cannot("has hardwired color values.");
6388 else
6389 color_edit();
6390 break;
6392 #if USE_SOFTKEYS
6393 case 'e':
6394 slk_test();
6395 break;
6397 #if USE_WIDEC_SUPPORT
6398 case 'E':
6399 wide_slk_test();
6400 break;
6401 #endif
6402 #endif
6404 case 'f':
6405 acs_display();
6406 break;
6408 #if USE_WIDEC_SUPPORT
6409 case 'F':
6410 wide_acs_display();
6411 break;
6412 #endif
6414 #if USE_LIBPANEL
6415 case 'o':
6416 demo_panels(init_panel, fill_panel);
6417 break;
6418 #endif
6420 #if USE_WIDEC_SUPPORT && USE_LIBPANEL
6421 case 'O':
6422 demo_panels(init_wide_panel, fill_wide_panel);
6423 break;
6424 #endif
6426 case 'g':
6427 acs_and_scroll();
6428 break;
6430 case 'i':
6431 flushinp_test(stdscr);
6432 break;
6434 case 'k':
6435 test_sgr_attributes();
6436 break;
6438 #if USE_LIBMENU
6439 case 'm':
6440 menu_test();
6441 break;
6442 #endif
6444 case 'p':
6445 demo_pad();
6446 break;
6448 #if USE_LIBFORM
6449 case 'r':
6450 demo_forms();
6451 break;
6452 #endif
6454 case 's':
6455 overlap_test();
6456 break;
6458 #if USE_LIBMENU && defined(TRACE)
6459 case 't':
6460 trace_set();
6461 break;
6462 #endif
6464 case '?':
6465 break;
6467 default:
6468 return FALSE;
6471 return TRUE;
6474 static void
6475 usage(void)
6477 static const char *const tbl[] =
6479 "Usage: ncurses [options]"
6481 ,"Options:"
6482 #ifdef NCURSES_VERSION
6483 ," -a f,b set default-colors (assumed white-on-black)"
6484 ," -d use default-colors if terminal supports them"
6485 #endif
6486 #if USE_SOFTKEYS
6487 ," -e fmt specify format for soft-keys test (e)"
6488 #endif
6489 #if HAVE_RIPOFFLINE
6490 ," -f rip-off footer line (can repeat)"
6491 ," -h rip-off header line (can repeat)"
6492 #endif
6493 ," -m do not use colors"
6494 ," -p file rgb values to use in 'd' rather than ncurses's builtin"
6495 #if USE_LIBPANEL
6496 ," -s msec specify nominal time for panel-demo (default: 1, to hold)"
6497 #endif
6498 #ifdef TRACE
6499 ," -t mask specify default trace-level (may toggle with ^T)"
6500 #endif
6502 size_t n;
6503 for (n = 0; n < SIZEOF(tbl); n++)
6504 fprintf(stderr, "%s\n", tbl[n]);
6505 ExitProgram(EXIT_FAILURE);
6508 static void
6509 set_terminal_modes(void)
6511 noraw();
6512 cbreak();
6513 noecho();
6514 scrollok(stdscr, TRUE);
6515 idlok(stdscr, TRUE);
6516 keypad(stdscr, TRUE);
6519 #ifdef SIGUSR1
6520 static RETSIGTYPE
6521 announce_sig(int sig)
6523 (void) fprintf(stderr, "Handled signal %d\r\n", sig);
6525 #endif
6527 #if HAVE_RIPOFFLINE
6528 static int
6529 rip_footer(WINDOW *win, int cols)
6531 wbkgd(win, A_REVERSE);
6532 werase(win);
6533 wmove(win, 0, 0);
6534 wprintw(win, "footer: window %p, %d columns", (void *) win, cols);
6535 wnoutrefresh(win);
6536 return OK;
6539 static int
6540 rip_header(WINDOW *win, int cols)
6542 wbkgd(win, A_REVERSE);
6543 werase(win);
6544 wmove(win, 0, 0);
6545 wprintw(win, "header: window %p, %d columns", (void *) win, cols);
6546 wnoutrefresh(win);
6547 return OK;
6549 #endif /* HAVE_RIPOFFLINE */
6551 static void
6552 main_menu(bool top)
6554 char command;
6556 do {
6557 (void) puts("This is the ncurses main menu");
6558 (void) puts("a = keyboard and mouse input test");
6559 #if USE_WIDEC_SUPPORT
6560 (void) puts("A = wide-character keyboard and mouse input test");
6561 #endif
6562 (void) puts("b = character attribute test");
6563 #if USE_WIDEC_SUPPORT
6564 (void) puts("B = wide-character attribute test");
6565 #endif
6566 (void) puts("c = color test pattern");
6567 #if USE_WIDEC_SUPPORT
6568 (void) puts("C = color test pattern using wide-character calls");
6569 #endif
6570 if (top)
6571 (void) puts("d = edit RGB color values");
6572 #if USE_SOFTKEYS
6573 (void) puts("e = exercise soft keys");
6574 #if USE_WIDEC_SUPPORT
6575 (void) puts("E = exercise soft keys using wide-characters");
6576 #endif
6577 #endif
6578 (void) puts("f = display ACS characters");
6579 #if USE_WIDEC_SUPPORT
6580 (void) puts("F = display Wide-ACS characters");
6581 #endif
6582 (void) puts("g = display windows and scrolling");
6583 (void) puts("i = test of flushinp()");
6584 (void) puts("k = display character attributes");
6585 #if USE_LIBMENU
6586 (void) puts("m = menu code test");
6587 #endif
6588 #if USE_LIBPANEL
6589 (void) puts("o = exercise panels library");
6590 #if USE_WIDEC_SUPPORT
6591 (void) puts("O = exercise panels with wide-characters");
6592 #endif
6593 #endif
6594 (void) puts("p = exercise pad features");
6595 (void) puts("q = quit");
6596 #if USE_LIBFORM
6597 (void) puts("r = exercise forms code");
6598 #endif
6599 (void) puts("s = overlapping-refresh test");
6600 #if USE_LIBMENU && defined(TRACE)
6601 (void) puts("t = set trace level");
6602 #endif
6603 (void) puts("? = repeat this command summary");
6605 (void) fputs("> ", stdout);
6606 (void) fflush(stdout); /* necessary under SVr4 curses */
6609 * This used to be an 'fgets()' call (until 1996/10). However with
6610 * some runtime libraries, mixing stream I/O and 'read()' causes the
6611 * input stream to be flushed when switching between the two.
6613 command = 0;
6614 for (;;) {
6615 char ch = '\0';
6616 if (read(fileno(stdin), &ch, 1) <= 0) {
6617 if (command == 0)
6618 command = 'q';
6619 break;
6620 } else if (command == 0 && !isspace(UChar(ch))) {
6621 command = ch;
6622 } else if (ch == '\n' || ch == '\r') {
6623 if ((command == 'd') && !top) {
6624 (void) fputs("Do not nest test-d\n", stdout);
6625 command = 0;
6627 if (command != 0)
6628 break;
6629 (void) fputs("> ", stdout);
6630 (void) fflush(stdout);
6634 if (do_single_test(command)) {
6636 * This may be overkill; it's intended to reset everything back
6637 * to the initial terminal modes so that tests don't get in
6638 * each other's way.
6640 flushinp();
6641 set_terminal_modes();
6642 reset_prog_mode();
6643 clear();
6644 refresh();
6645 endwin();
6646 if (command == '?') {
6647 (void) puts("This is the ncurses capability tester.");
6648 (void)
6649 puts("You may select a test from the main menu by typing the");
6650 (void)
6651 puts("key letter of the choice (the letter to left of the =)");
6652 (void)
6653 puts("at the > prompt. Type `q' to exit.");
6655 continue;
6657 } while
6658 (command != 'q');
6661 /*+-------------------------------------------------------------------------
6662 main(argc,argv)
6663 --------------------------------------------------------------------------*/
6665 #define okCOLOR(n) ((n) >= 0 && (n) < max_colors)
6666 #define okRGB(n) ((n) >= 0 && (n) <= 1000)
6669 main(int argc, char *argv[])
6671 int c;
6672 int my_e_param = 1;
6673 #ifdef NCURSES_VERSION
6674 int default_fg = COLOR_WHITE;
6675 int default_bg = COLOR_BLACK;
6676 bool assumed_colors = FALSE;
6677 bool default_colors = FALSE;
6678 #endif
6679 char *palette_file = 0;
6680 bool monochrome = FALSE;
6682 setlocale(LC_ALL, "");
6684 while ((c = getopt(argc, argv, "a:de:fhmp:s:t:")) != -1) {
6685 switch (c) {
6686 #ifdef NCURSES_VERSION
6687 case 'a':
6688 assumed_colors = TRUE;
6689 sscanf(optarg, "%d,%d", &default_fg, &default_bg);
6690 break;
6691 case 'd':
6692 default_colors = TRUE;
6693 break;
6694 #endif
6695 case 'e':
6696 my_e_param = atoi(optarg);
6697 #ifdef NCURSES_VERSION
6698 if (my_e_param > 3) /* allow extended layouts */
6699 usage();
6700 #else
6701 if (my_e_param > 1)
6702 usage();
6703 #endif
6704 break;
6705 #if HAVE_RIPOFFLINE
6706 case 'f':
6707 ripoffline(-1, rip_footer);
6708 break;
6709 case 'h':
6710 ripoffline(1, rip_header);
6711 break;
6712 #endif /* HAVE_RIPOFFLINE */
6713 case 'm':
6714 monochrome = TRUE;
6715 break;
6716 case 'p':
6717 palette_file = optarg;
6718 break;
6719 #if USE_LIBPANEL
6720 case 's':
6721 nap_msec = (int) atol(optarg);
6722 break;
6723 #endif
6724 #ifdef TRACE
6725 case 't':
6726 save_trace = (unsigned) strtol(optarg, 0, 0);
6727 break;
6728 #endif
6729 default:
6730 usage();
6735 * If there's no menus (unlikely for ncurses!), then we'll have to set
6736 * tracing on initially, just in case the user wants to test something that
6737 * doesn't involve wGetchar.
6739 #ifdef TRACE
6740 /* enable debugging */
6741 #if !USE_LIBMENU
6742 trace(save_trace);
6743 #else
6744 if (!isatty(fileno(stdin)))
6745 trace(save_trace);
6746 #endif /* USE_LIBMENU */
6747 #endif /* TRACE */
6749 #if USE_SOFTKEYS
6750 /* tell it we're going to play with soft keys */
6751 slk_init(my_e_param);
6752 #endif
6754 #ifdef SIGUSR1
6755 /* set up null signal catcher so we can see what interrupts to getch do */
6756 signal(SIGUSR1, announce_sig);
6757 #endif
6759 /* we must initialize the curses data structure only once */
6760 initscr();
6761 bkgdset(BLANK);
6763 /* tests, in general, will want these modes */
6764 use_colors = monochrome ? FALSE : has_colors();
6766 if (use_colors) {
6767 start_color();
6768 #ifdef NCURSES_VERSION_PATCH
6769 max_colors = COLORS; /* was > 16 ? 16 : COLORS */
6770 #if HAVE_USE_DEFAULT_COLORS
6771 if (default_colors) {
6772 use_default_colors();
6773 min_colors = -1;
6775 #if NCURSES_VERSION_PATCH >= 20000708
6776 if (assumed_colors)
6777 assume_default_colors(default_fg, default_bg);
6778 #endif
6779 #endif
6780 #else /* normal SVr4 curses */
6781 max_colors = COLORS; /* was > 8 ? 8 : COLORS */
6782 #endif
6783 max_pairs = COLOR_PAIRS; /* was > 256 ? 256 : COLOR_PAIRS */
6785 if (can_change_color()) {
6786 short cp;
6787 all_colors = typeMalloc(RGB_DATA, (unsigned) max_colors);
6788 for (cp = 0; cp < max_colors; ++cp) {
6789 color_content(cp,
6790 &all_colors[cp].red,
6791 &all_colors[cp].green,
6792 &all_colors[cp].blue);
6794 if (palette_file != 0) {
6795 FILE *fp = fopen(palette_file, "r");
6796 if (fp != 0) {
6797 char buffer[BUFSIZ];
6798 int red, green, blue;
6799 int scale = 1000;
6800 while (fgets(buffer, sizeof(buffer), fp) != 0) {
6801 if (sscanf(buffer, "scale:%d", &c) == 1) {
6802 scale = c;
6803 } else if (sscanf(buffer, "%d:%d %d %d",
6805 &red,
6806 &green,
6807 &blue) == 4
6808 && okCOLOR(c)
6809 && okRGB(red)
6810 && okRGB(green)
6811 && okRGB(blue)) {
6812 all_colors[c].red = (short) ((red * 1000) / scale);
6813 all_colors[c].green = (short) ((green * 1000) / scale);
6814 all_colors[c].blue = (short) ((blue * 1000) / scale);
6817 fclose(fp);
6822 set_terminal_modes();
6823 def_prog_mode();
6826 * Return to terminal mode, so we're guaranteed of being able to
6827 * select terminal commands even if the capabilities are wrong.
6829 endwin();
6831 #if HAVE_CURSES_VERSION
6832 (void) printf("Welcome to %s. Press ? for help.\n", curses_version());
6833 #elif defined(NCURSES_VERSION_MAJOR) && defined(NCURSES_VERSION_MINOR) && defined(NCURSES_VERSION_PATCH)
6834 (void) printf("Welcome to ncurses %d.%d.%d. Press ? for help.\n",
6835 NCURSES_VERSION_MAJOR,
6836 NCURSES_VERSION_MINOR,
6837 NCURSES_VERSION_PATCH);
6838 #else
6839 (void) puts("Welcome to ncurses. Press ? for help.");
6840 #endif
6842 main_menu(TRUE);
6844 ExitProgram(EXIT_SUCCESS);
6847 /* ncurses.c ends here */