1/**************************************************************************** 2 * Copyright (c) 1998-2004,2005 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/**************************************************************************** 29 30NAME 31 ncurses.c --- ncurses library exerciser 32 33SYNOPSIS 34 ncurses 35 36DESCRIPTION 37 An interactive test module for the ncurses library. 38 39AUTHOR 40 Author: Eric S. Raymond <esr@snark.thyrsus.com> 1993 41 Thomas E. Dickey (beginning revision 1.27 in 1996). 42 43$Id: ncurses.c,v 1.253 2005/10/01 16:00:56 tom Exp $ 44 45***************************************************************************/ 46 47#include <test.priv.h> 48 49#if HAVE_GETTIMEOFDAY 50#if HAVE_SYS_TIME_H && HAVE_SYS_TIME_SELECT 51#include <sys/time.h> 52#endif 53#if HAVE_SYS_SELECT_H 54#include <sys/select.h> 55#endif 56#endif 57 58#if USE_LIBPANEL 59#include <panel.h> 60#endif 61 62#if USE_LIBMENU 63#include <menu.h> 64#endif 65 66#if USE_LIBFORM 67#include <form.h> 68#endif 69 70#ifdef NCURSES_VERSION 71 72#ifdef TRACE 73static unsigned save_trace = TRACE_ORDINARY | TRACE_CALLS; 74extern unsigned _nc_tracing; 75#endif 76 77#else 78 79#define mmask_t chtype /* not specified in XSI */ 80 81#ifdef CURSES_ACS_ARRAY 82#define ACS_S3 (CURSES_ACS_ARRAY['p']) /* scan line 3 */ 83#define ACS_S7 (CURSES_ACS_ARRAY['r']) /* scan line 7 */ 84#define ACS_LEQUAL (CURSES_ACS_ARRAY['y']) /* less/equal */ 85#define ACS_GEQUAL (CURSES_ACS_ARRAY['z']) /* greater/equal */ 86#define ACS_PI (CURSES_ACS_ARRAY['{']) /* Pi */ 87#define ACS_NEQUAL (CURSES_ACS_ARRAY['|']) /* not equal */ 88#define ACS_STERLING (CURSES_ACS_ARRAY['}']) /* UK pound sign */ 89#else 90#define ACS_S3 (A_ALTCHARSET + 'p') /* scan line 3 */ 91#define ACS_S7 (A_ALTCHARSET + 'r') /* scan line 7 */ 92#define ACS_LEQUAL (A_ALTCHARSET + 'y') /* less/equal */ 93#define ACS_GEQUAL (A_ALTCHARSET + 'z') /* greater/equal */ 94#define ACS_PI (A_ALTCHARSET + '{') /* Pi */ 95#define ACS_NEQUAL (A_ALTCHARSET + '|') /* not equal */ 96#define ACS_STERLING (A_ALTCHARSET + '}') /* UK pound sign */ 97#endif 98 99#ifdef CURSES_WACS_ARRAY 100#define WACS_S3 (&(CURSES_WACS_ARRAY['p'])) /* scan line 3 */ 101#define WACS_S7 (&(CURSES_WACS_ARRAY['r'])) /* scan line 7 */ 102#define WACS_LEQUAL (&(CURSES_WACS_ARRAY['y'])) /* less/equal */ 103#define WACS_GEQUAL (&(CURSES_WACS_ARRAY['z'])) /* greater/equal */ 104#define WACS_PI (&(CURSES_WACS_ARRAY['{'])) /* Pi */ 105#define WACS_NEQUAL (&(CURSES_WACS_ARRAY['|'])) /* not equal */ 106#define WACS_STERLING (&(CURSES_WACS_ARRAY['}'])) /* UK pound sign */ 107#endif 108 109#endif 110 111#define P(string) printw("%s\n", string) 112 113#define BLANK ' ' /* this is the background character */ 114 115#undef max_colors 116static int max_colors; /* the actual number of colors we'll use */ 117static int min_colors; /* the minimum color code */ 118 119#undef max_pairs 120static int max_pairs; /* ...and the number of color pairs */ 121 122typedef struct { 123 short red; 124 short green; 125 short blue; 126} RGB_DATA; 127 128static RGB_DATA *all_colors; 129 130static void main_menu(bool); 131 132/* The behavior of mvhline, mvvline for negative/zero length is unspecified, 133 * though we can rely on negative x/y values to stop the macro. 134 */ 135static void 136do_h_line(int y, int x, chtype c, int to) 137{ 138 if ((to) > (x)) 139 mvhline(y, x, c, (to) - (x)); 140} 141 142static void 143do_v_line(int y, int x, chtype c, int to) 144{ 145 if ((to) > (y)) 146 mvvline(y, x, c, (to) - (y)); 147} 148 149static void 150Repaint(void) 151{ 152 touchwin(stdscr); 153 touchwin(curscr); 154 wrefresh(curscr); 155} 156 157/* Common function to allow ^T to toggle trace-mode in the middle of a test 158 * so that trace-files can be made smaller. 159 */ 160static int 161wGetchar(WINDOW *win) 162{ 163 int c; 164#ifdef TRACE 165 while ((c = wgetch(win)) == CTRL('T')) { 166 if (_nc_tracing) { 167 save_trace = _nc_tracing; 168 _tracef("TOGGLE-TRACING OFF"); 169 _nc_tracing = 0; 170 } else { 171 _nc_tracing = save_trace; 172 } 173 trace(_nc_tracing); 174 if (_nc_tracing) 175 _tracef("TOGGLE-TRACING ON"); 176 } 177#else 178 c = wgetch(win); 179#endif 180 return c; 181} 182#define Getchar() wGetchar(stdscr) 183 184/* replaces wgetnstr(), since we want to be able to edit values */ 185static void 186wGetstring(WINDOW *win, char *buffer, int limit) 187{ 188 int y0, x0, x, ch; 189 bool done = FALSE; 190 191 echo(); 192 getyx(win, y0, x0); 193 wattrset(win, A_REVERSE); 194 195 x = strlen(buffer); 196 while (!done) { 197 if (x > (int) strlen(buffer)) 198 x = (int) strlen(buffer); 199 wmove(win, y0, x0); 200 wprintw(win, "%-*s", limit, buffer); 201 wmove(win, y0, x0 + x); 202 switch (ch = wGetchar(win)) { 203 case '\n': 204 case KEY_ENTER: 205 done = TRUE; 206 break; 207 case CTRL('U'): 208 *buffer = '\0'; 209 break; 210 case '\b': 211 case KEY_BACKSPACE: 212 case KEY_DC: 213 if (x > 0) { 214 int j; 215 for (j = --x; (buffer[j] = buffer[j + 1]) != '\0'; ++j) { 216 ; 217 } 218 } else { 219 beep(); 220 } 221 break; 222 case KEY_LEFT: 223 if (x > 0) { 224 --x; 225 } else { 226 flash(); 227 } 228 break; 229 case KEY_RIGHT: 230 ++x; 231 break; 232 default: 233 if (!isprint(ch) || ch >= KEY_MIN) { 234 beep(); 235 } else if ((int) strlen(buffer) < limit) { 236 int j; 237 for (j = strlen(buffer) + 1; j > x; --j) { 238 buffer[j] = buffer[j - 1]; 239 } 240 buffer[x++] = ch; 241 } else { 242 flash(); 243 } 244 } 245 } 246 247 wattroff(win, A_REVERSE); 248 wmove(win, y0, x0); 249 noecho(); 250} 251 252#if USE_WIDEC_SUPPORT 253static int 254wGet_wchar(WINDOW *win, wint_t *result) 255{ 256 int c; 257#ifdef TRACE 258 while ((c = wget_wch(win, result)) == CTRL('T')) { 259 if (_nc_tracing) { 260 save_trace = _nc_tracing; 261 _tracef("TOGGLE-TRACING OFF"); 262 _nc_tracing = 0; 263 } else { 264 _nc_tracing = save_trace; 265 } 266 trace(_nc_tracing); 267 if (_nc_tracing) 268 _tracef("TOGGLE-TRACING ON"); 269 } 270#else 271 c = wget_wch(win, result); 272#endif 273 return c; 274} 275#define Get_wchar(result) wGet_wchar(stdscr, result) 276 277/* replaces wgetn_wstr(), since we want to be able to edit values */ 278static void 279wGet_wstring(WINDOW *win, wchar_t *buffer, int limit) 280{ 281 int y0, x0, x; 282 wint_t ch; 283 bool done = FALSE; 284 bool fkey = FALSE; 285 286 echo(); 287 getyx(win, y0, x0); 288 wattrset(win, A_REVERSE); 289 290 x = wcslen(buffer); 291 while (!done) { 292 if (x > (int) wcslen(buffer)) 293 x = (int) wcslen(buffer); 294 295 /* clear the "window' */ 296 wmove(win, y0, x0); 297 wprintw(win, "%*s", limit, " "); 298 299 /* write the existing buffer contents */ 300 wmove(win, y0, x0); 301 waddnwstr(win, buffer, limit); 302 303 /* positions the cursor past character 'x' */ 304 wmove(win, y0, x0); 305 waddnwstr(win, buffer, x); 306 307 switch (wGet_wchar(win, &ch)) { 308 case KEY_CODE_YES: 309 fkey = TRUE; 310 switch (ch) { 311 case KEY_ENTER: 312 ch = '\n'; 313 fkey = FALSE; 314 break; 315 case KEY_BACKSPACE: 316 case KEY_DC: 317 ch = '\b'; 318 fkey = FALSE; 319 break; 320 case KEY_LEFT: 321 case KEY_RIGHT: 322 break; 323 default: 324 ch = (wint_t) -1; 325 break; 326 } 327 break; 328 case OK: 329 fkey = FALSE; 330 break; 331 default: 332 ch = (wint_t) -1; 333 fkey = TRUE; 334 break; 335 } 336 337 switch (ch) { 338 case '\n': 339 done = TRUE; 340 break; 341 case CTRL('U'): 342 *buffer = '\0'; 343 break; 344 case '\b': 345 if (x > 0) { 346 int j; 347 for (j = --x; (buffer[j] = buffer[j + 1]) != '\0'; ++j) { 348 ; 349 } 350 } else { 351 beep(); 352 } 353 break; 354 case KEY_LEFT: 355 if (x > 0) { 356 --x; 357 } else { 358 beep(); 359 } 360 break; 361 case KEY_RIGHT: 362 ++x; 363 break; 364 default: 365 if (fkey) { 366 beep(); 367 } else if ((int) wcslen(buffer) < limit) { 368 int j; 369 for (j = wcslen(buffer) + 1; j > x; --j) { 370 buffer[j] = buffer[j - 1]; 371 } 372 buffer[x++] = ch; 373 } else { 374 beep(); 375 } 376 } 377 } 378 379 wattroff(win, A_REVERSE); 380 wmove(win, y0, x0); 381 noecho(); 382} 383 384#endif 385 386static void 387Pause(void) 388{ 389 move(LINES - 1, 0); 390 addstr("Press any key to continue... "); 391 (void) Getchar(); 392} 393 394static void 395Cannot(const char *what) 396{ 397 printw("\nThis %s terminal %s\n\n", getenv("TERM"), what); 398 Pause(); 399} 400 401static void 402ShellOut(bool message) 403{ 404 if (message) 405 addstr("Shelling out..."); 406 def_prog_mode(); 407 endwin(); 408 system("sh"); 409 if (message) 410 addstr("returned from shellout.\n"); 411 refresh(); 412} 413 414#ifdef NCURSES_MOUSE_VERSION 415/* 416 * This function is the same as _tracemouse(), but we cannot count on that 417 * being available in the non-debug library. 418 */ 419static const char * 420mouse_decode(MEVENT const *ep) 421{ 422 static char buf[80 + (5 * 10) + (32 * 15)]; 423 424 (void) sprintf(buf, "id %2d at (%2d, %2d, %2d) state %4lx = {", 425 ep->id, ep->x, ep->y, ep->z, (unsigned long) ep->bstate); 426 427#define SHOW(m, s) if ((ep->bstate & m)==m) {strcat(buf,s); strcat(buf, ", ");} 428 429 SHOW(BUTTON1_RELEASED, "release-1"); 430 SHOW(BUTTON1_PRESSED, "press-1"); 431 SHOW(BUTTON1_CLICKED, "click-1"); 432 SHOW(BUTTON1_DOUBLE_CLICKED, "doubleclick-1"); 433 SHOW(BUTTON1_TRIPLE_CLICKED, "tripleclick-1"); 434#if NCURSES_MOUSE_VERSION == 1 435 SHOW(BUTTON1_RESERVED_EVENT, "reserved-1"); 436#endif 437 438 SHOW(BUTTON2_RELEASED, "release-2"); 439 SHOW(BUTTON2_PRESSED, "press-2"); 440 SHOW(BUTTON2_CLICKED, "click-2"); 441 SHOW(BUTTON2_DOUBLE_CLICKED, "doubleclick-2"); 442 SHOW(BUTTON2_TRIPLE_CLICKED, "tripleclick-2"); 443#if NCURSES_MOUSE_VERSION == 1 444 SHOW(BUTTON2_RESERVED_EVENT, "reserved-2"); 445#endif 446 447 SHOW(BUTTON3_RELEASED, "release-3"); 448 SHOW(BUTTON3_PRESSED, "press-3"); 449 SHOW(BUTTON3_CLICKED, "click-3"); 450 SHOW(BUTTON3_DOUBLE_CLICKED, "doubleclick-3"); 451 SHOW(BUTTON3_TRIPLE_CLICKED, "tripleclick-3"); 452#if NCURSES_MOUSE_VERSION == 1 453 SHOW(BUTTON3_RESERVED_EVENT, "reserved-3"); 454#endif 455 456 SHOW(BUTTON4_RELEASED, "release-4"); 457 SHOW(BUTTON4_PRESSED, "press-4"); 458 SHOW(BUTTON4_CLICKED, "click-4"); 459 SHOW(BUTTON4_DOUBLE_CLICKED, "doubleclick-4"); 460 SHOW(BUTTON4_TRIPLE_CLICKED, "tripleclick-4"); 461#if NCURSES_MOUSE_VERSION == 1 462 SHOW(BUTTON4_RESERVED_EVENT, "reserved-4"); 463#endif 464 465#if NCURSES_MOUSE_VERSION == 2 466 SHOW(BUTTON5_RELEASED, "release-5"); 467 SHOW(BUTTON5_PRESSED, "press-5"); 468 SHOW(BUTTON5_CLICKED, "click-5"); 469 SHOW(BUTTON5_DOUBLE_CLICKED, "doubleclick-5"); 470 SHOW(BUTTON5_TRIPLE_CLICKED, "tripleclick-5"); 471#endif 472 473 SHOW(BUTTON_CTRL, "ctrl"); 474 SHOW(BUTTON_SHIFT, "shift"); 475 SHOW(BUTTON_ALT, "alt"); 476 SHOW(ALL_MOUSE_EVENTS, "all-events"); 477 SHOW(REPORT_MOUSE_POSITION, "position"); 478 479#undef SHOW 480 481 if (buf[strlen(buf) - 1] == ' ') 482 buf[strlen(buf) - 2] = '\0'; 483 (void) strcat(buf, "}"); 484 return (buf); 485} 486#endif /* NCURSES_MOUSE_VERSION */ 487 488/**************************************************************************** 489 * 490 * Character input test 491 * 492 ****************************************************************************/ 493 494static void 495setup_getch(WINDOW *win, bool flags[]) 496{ 497 keypad(win, flags['k']); /* should be redundant, but for testing */ 498 meta(win, flags['m']); /* force this to a known state */ 499 if (flags['e']) 500 echo(); 501 else 502 noecho(); 503} 504 505static void 506wgetch_help(WINDOW *win, bool flags[]) 507{ 508 static const char *help[] = 509 { 510 "e -- toggle echo mode" 511 ,"g -- triggers a getstr test" 512 ,"k -- toggle keypad/literal mode" 513 ,"m -- toggle meta (7-bit/8-bit) mode" 514 ,"q -- quit (x also exits)" 515 ,"s -- shell out\n" 516 ,"w -- create a new window" 517#ifdef SIGTSTP 518 ,"z -- suspend this process" 519#endif 520 }; 521 int y, x; 522 unsigned chk = ((SIZEOF(help) + 1) / 2); 523 unsigned n; 524 525 getyx(win, y, x); 526 move(0, 0); 527 printw("Type any key to see its %s value. Also:\n", 528 flags['k'] ? "keypad" : "literal"); 529 for (n = 0; n < SIZEOF(help); ++n) { 530 int row = 1 + (n % chk); 531 int col = (n >= chk) ? COLS / 2 : 0; 532 int flg = ((strstr(help[n], "toggle") != 0) 533 && (flags[UChar(*help[n])] != FALSE)); 534 if (flg) 535 standout(); 536 mvprintw(row, col, "%s", help[n]); 537 if (col == 0) 538 clrtoeol(); 539 if (flg) 540 standend(); 541 } 542 wrefresh(stdscr); 543 wmove(win, y, x); 544} 545 546static void 547wgetch_wrap(WINDOW *win, int first_y) 548{ 549 int last_y = getmaxy(win) - 1; 550 int y = getcury(win) + 1; 551 552 if (y >= last_y) 553 y = first_y; 554 wmove(win, y, 0); 555 wclrtoeol(win); 556} 557 558#if defined(NCURSES_VERSION) && defined(KEY_RESIZE) && HAVE_WRESIZE 559typedef struct { 560 WINDOW *text; 561 WINDOW *frame; 562} WINSTACK; 563 564static WINSTACK *winstack = 0; 565static unsigned len_winstack = 0; 566 567static void 568remember_boxes(unsigned level, WINDOW *txt_win, WINDOW *box_win) 569{ 570 unsigned need = (level + 1) * 2; 571 572 if (winstack == 0) { 573 len_winstack = 20; 574 winstack = (WINSTACK *) malloc(len_winstack * sizeof(WINSTACK)); 575 } else if (need >= len_winstack) { 576 len_winstack = need; 577 winstack = (WINSTACK *) realloc(winstack, len_winstack * sizeof(WINSTACK)); 578 } 579 winstack[level].text = txt_win; 580 winstack[level].frame = box_win; 581} 582 583/* 584 * For wgetch_test(), we create pairs of windows - one for a box, one for text. 585 * Resize both and paint the box in the parent. 586 */ 587static void 588resize_boxes(unsigned level, WINDOW *win) 589{ 590 unsigned n; 591 int base = 5; 592 int high = LINES - base; 593 int wide = COLS; 594 595 touchwin(stdscr); 596 wnoutrefresh(stdscr); 597 598 /* FIXME: this chunk should be done in resizeterm() */ 599 slk_touch(); 600 slk_clear(); 601 slk_noutrefresh(); 602 603 for (n = 0; n < level; ++n) { 604 wresize(winstack[n].frame, high, wide); 605 wresize(winstack[n].text, high - 2, wide - 2); 606 high -= 2; 607 wide -= 2; 608 werase(winstack[n].text); 609 box(winstack[n].frame, 0, 0); 610 wnoutrefresh(winstack[n].frame); 611 wprintw(winstack[n].text, 612 "size %dx%d\n", 613 getmaxy(winstack[n].text), 614 getmaxx(winstack[n].text)); 615 wnoutrefresh(winstack[n].text); 616 if (winstack[n].text == win) 617 break; 618 } 619 doupdate(); 620} 621#else 622#define remember_boxes(level,text,frame) /* nothing */ 623#endif 624 625static void 626wgetch_test(unsigned level, WINDOW *win, int delay) 627{ 628 char buf[BUFSIZ]; 629 int first_y, first_x; 630 int c; 631 int incount = 0; 632 bool flags[256]; 633 bool blocking = (delay < 0); 634 635 memset(flags, FALSE, sizeof(flags)); 636 flags[UChar('k')] = (win == stdscr); 637 638 setup_getch(win, flags); 639 wtimeout(win, delay); 640 getyx(win, first_y, first_x); 641 642 wgetch_help(win, flags); 643 wsetscrreg(win, first_y, getmaxy(win) - 1); 644 scrollok(win, TRUE); 645 646 for (;;) { 647 while ((c = wGetchar(win)) == ERR) { 648 incount++; 649 if (blocking) { 650 (void) wprintw(win, "%05d: input error", incount); 651 break; 652 } else { 653 (void) wprintw(win, "%05d: input timed out", incount); 654 } 655 wgetch_wrap(win, first_y); 656 } 657 if (c == ERR && blocking) { 658 wprintw(win, "ERR"); 659 wgetch_wrap(win, first_y); 660 } else if (c == 'x' || c == 'q') { 661 break; 662 } else if (c == 'e') { 663 flags[UChar('e')] = !flags[UChar('e')]; 664 setup_getch(win, flags); 665 wgetch_help(win, flags); 666 } else if (c == 'g') { 667 waddstr(win, "getstr test: "); 668 echo(); 669 wgetnstr(win, buf, sizeof(buf) - 1); 670 noecho(); 671 wprintw(win, "I saw %d characters:\n\t`%s'.", (int) strlen(buf), buf); 672 wclrtoeol(win); 673 wgetch_wrap(win, first_y); 674 } else if (c == 'k') { 675 flags[UChar('k')] = !flags[UChar('k')]; 676 setup_getch(win, flags); 677 wgetch_help(win, flags); 678 } else if (c == 'm') { 679 flags[UChar('m')] = !flags[UChar('m')]; 680 setup_getch(win, flags); 681 wgetch_help(win, flags); 682 } else if (c == 's') { 683 ShellOut(TRUE); 684 } else if (c == 'w') { 685 int high = getmaxy(win) - 1 - first_y + 1; 686 int wide = getmaxx(win) - first_x; 687 int old_y, old_x; 688 int new_y = first_y + getbegy(win); 689 int new_x = first_x + getbegx(win); 690 691 getyx(win, old_y, old_x); 692 if (high > 2 && wide > 2) { 693 WINDOW *wb = newwin(high, wide, new_y, new_x); 694 WINDOW *wi = newwin(high - 2, wide - 2, new_y + 1, new_x + 1); 695 696 box(wb, 0, 0); 697 wrefresh(wb); 698 wmove(wi, 0, 0); 699 remember_boxes(level, wi, wb); 700 wgetch_test(level + 1, wi, delay); 701 delwin(wi); 702 delwin(wb); 703 704 wgetch_help(win, flags); 705 wmove(win, old_y, old_x); 706 touchwin(win); 707 wrefresh(win); 708 doupdate(); 709 } 710#ifdef SIGTSTP 711 } else if (c == 'z') { 712 kill(getpid(), SIGTSTP); 713#endif 714 } else { 715 wprintw(win, "Key pressed: %04o ", c); 716#ifdef NCURSES_MOUSE_VERSION 717 if (c == KEY_MOUSE) { 718 int y, x; 719 MEVENT event; 720 721 getmouse(&event); 722 wprintw(win, "KEY_MOUSE, %s", mouse_decode(&event)); 723 getyx(win, y, x); 724 move(event.y, event.x); 725 addch('*'); 726 wmove(win, y, x); 727 } else 728#endif /* NCURSES_MOUSE_VERSION */ 729 if (c >= KEY_MIN) { 730#if defined(NCURSES_VERSION) && defined(KEY_RESIZE) && HAVE_WRESIZE 731 if (c == KEY_RESIZE) { 732 resize_boxes(level, win); 733 } 734#endif 735 (void) waddstr(win, keyname(c)); 736 } else if (c > 0x80) { 737 unsigned c2 = (c & 0x7f); 738 if (isprint(c2)) 739 (void) wprintw(win, "M-%c", UChar(c2)); 740 else 741 (void) wprintw(win, "M-%s", unctrl(c2)); 742 waddstr(win, " (high-half character)"); 743 } else { 744 if (isprint(c)) 745 (void) wprintw(win, "%c (ASCII printable character)", c); 746 else 747 (void) wprintw(win, "%s (ASCII control character)", 748 unctrl(UChar(c))); 749 } 750 wgetch_wrap(win, first_y); 751 } 752 } 753 754 wtimeout(win, -1); 755} 756 757static int 758begin_getch_test(void) 759{ 760 char buf[BUFSIZ]; 761 int delay; 762 763 refresh(); 764 765#ifdef NCURSES_MOUSE_VERSION 766 mousemask(ALL_MOUSE_EVENTS, (mmask_t *) 0); 767#endif 768 769 (void) printw("Delay in 10ths of a second (<CR> for blocking input)? "); 770 echo(); 771 getnstr(buf, sizeof(buf) - 1); 772 noecho(); 773 nonl(); 774 775 if (isdigit(UChar(buf[0]))) { 776 delay = atoi(buf) * 100; 777 } else { 778 delay = -1; 779 } 780 raw(); 781 move(5, 0); 782 return delay; 783} 784 785static void 786finish_getch_test(void) 787{ 788#ifdef NCURSES_MOUSE_VERSION 789 mousemask(0, (mmask_t *) 0); 790#endif 791 erase(); 792 noraw(); 793 nl(); 794 endwin(); 795} 796 797static void 798getch_test(void) 799{ 800 int delay = begin_getch_test(); 801 wgetch_test(0, stdscr, delay); 802 finish_getch_test(); 803} 804 805#if USE_WIDEC_SUPPORT 806/* 807 * For wgetch_test(), we create pairs of windows - one for a box, one for text. 808 * Resize both and paint the box in the parent. 809 */ 810#ifdef KEY_RESIZE 811static void 812resize_wide_boxes(unsigned level, WINDOW *win) 813{ 814 unsigned n; 815 int base = 5; 816 int high = LINES - base; 817 int wide = COLS; 818 819 touchwin(stdscr); 820 wnoutrefresh(stdscr); 821 822 /* FIXME: this chunk should be done in resizeterm() */ 823 slk_touch(); 824 slk_clear(); 825 slk_noutrefresh(); 826 827 for (n = 0; n < level; ++n) { 828 wresize(winstack[n].frame, high, wide); 829 wresize(winstack[n].text, high - 2, wide - 2); 830 high -= 2; 831 wide -= 2; 832 werase(winstack[n].text); 833 box_set(winstack[n].frame, 0, 0); 834 wnoutrefresh(winstack[n].frame); 835 wprintw(winstack[n].text, 836 "size %dx%d\n", 837 getmaxy(winstack[n].text), 838 getmaxx(winstack[n].text)); 839 wnoutrefresh(winstack[n].text); 840 if (winstack[n].text == win) 841 break; 842 } 843 doupdate(); 844} 845#endif /* KEY_RESIZE */ 846 847static char * 848wcstos(const wchar_t *src) 849{ 850 int need; 851 mbstate_t state; 852 char *result = 0; 853 const wchar_t *tmp = src; 854 855 memset(&state, 0, sizeof(state)); 856 if ((need = wcsrtombs(0, &tmp, 0, &state)) > 0) { 857 unsigned have = need; 858 result = (char *) calloc(have + 1, 1); 859 tmp = src; 860 if (wcsrtombs(result, &tmp, have, &state) != have) { 861 free(result); 862 result = 0; 863 } 864 } 865 return result; 866} 867 868static void 869wget_wch_test(unsigned level, WINDOW *win, int delay) 870{ 871 wchar_t wchar_buf[BUFSIZ]; 872 wint_t wint_buf[BUFSIZ]; 873 int first_y, first_x; 874 wint_t c; 875 int incount = 0; 876 bool flags[256]; 877 bool blocking = (delay < 0); 878 int y, x, code; 879 char *temp; 880 881 memset(flags, FALSE, sizeof(flags)); 882 flags[UChar('k')] = (win == stdscr); 883 884 setup_getch(win, flags); 885 wtimeout(win, delay); 886 getyx(win, first_y, first_x); 887 888 wgetch_help(win, flags); 889 wsetscrreg(win, first_y, getmaxy(win) - 1); 890 scrollok(win, TRUE); 891 892 for (;;) { 893 while ((code = wGet_wchar(win, &c)) == ERR) { 894 incount++; 895 if (blocking) { 896 (void) wprintw(win, "%05d: input error", incount); 897 break; 898 } else { 899 (void) wprintw(win, "%05d: input timed out", incount); 900 } 901 wgetch_wrap(win, first_y); 902 } 903 if (code == ERR && blocking) { 904 wprintw(win, "ERR"); 905 wgetch_wrap(win, first_y); 906 } else if (c == 'x' || c == 'q') { 907 break; 908 } else if (c == 'e') { 909 flags[UChar('e')] = !flags[UChar('e')]; 910 setup_getch(win, flags); 911 wgetch_help(win, flags); 912 } else if (c == 'g') { 913 waddstr(win, "getstr test: "); 914 echo(); 915 code = wgetn_wstr(win, wint_buf, sizeof(wint_buf) - 1); 916 noecho(); 917 if (code == ERR) { 918 wprintw(win, "wgetn_wstr returns an error."); 919 } else { 920 int n; 921 for (n = 0; (wchar_buf[n] = wint_buf[n]) != 0; ++n) ; 922 if ((temp = wcstos(wchar_buf)) != 0) { 923 wprintw(win, "I saw %d characters:\n\t`%s'.", 924 wcslen(wchar_buf), temp); 925 free(temp); 926 } else { 927 wprintw(win, "I saw %d characters (cannot convert).", 928 wcslen(wchar_buf)); 929 } 930 } 931 wclrtoeol(win); 932 wgetch_wrap(win, first_y); 933 } else if (c == 'k') { 934 flags[UChar('k')] = !flags[UChar('k')]; 935 setup_getch(win, flags); 936 wgetch_help(win, flags); 937 } else if (c == 'm') { 938 flags[UChar('m')] = !flags[UChar('m')]; 939 setup_getch(win, flags); 940 wgetch_help(win, flags); 941 } else if (c == 's') { 942 ShellOut(TRUE); 943 } else if (c == 'w') { 944 int high = getmaxy(win) - 1 - first_y + 1; 945 int wide = getmaxx(win) - first_x; 946 int old_y, old_x; 947 int new_y = first_y + getbegy(win); 948 int new_x = first_x + getbegx(win); 949 950 getyx(win, old_y, old_x); 951 if (high > 2 && wide > 2) { 952 WINDOW *wb = newwin(high, wide, new_y, new_x); 953 WINDOW *wi = newwin(high - 2, wide - 2, new_y + 1, new_x + 1); 954 955 box_set(wb, 0, 0); 956 wrefresh(wb); 957 wmove(wi, 0, 0); 958 remember_boxes(level, wi, wb); 959 wget_wch_test(level + 1, wi, delay); 960 delwin(wi); 961 delwin(wb); 962 963 wgetch_help(win, flags); 964 wmove(win, old_y, old_x); 965 touchwin(win); 966 wrefresh(win); 967 } 968#ifdef SIGTSTP 969 } else if (c == 'z') { 970 kill(getpid(), SIGTSTP); 971#endif 972 } else { 973 wprintw(win, "Key pressed: %04o ", c); 974#ifdef NCURSES_MOUSE_VERSION 975 if (c == KEY_MOUSE) { 976 MEVENT event; 977 978 getmouse(&event); 979 wprintw(win, "KEY_MOUSE, %s", mouse_decode(&event)); 980 getyx(win, y, x); 981 move(event.y, event.x); 982 addch('*'); 983 wmove(win, y, x); 984 } else 985#endif /* NCURSES_MOUSE_VERSION */ 986 if (code == KEY_CODE_YES) { 987#ifdef KEY_RESIZE 988 if (c == KEY_RESIZE) { 989 resize_wide_boxes(level, win); 990 } 991#endif 992 (void) waddstr(win, key_name((wchar_t) c)); 993 } else { 994 if (c < 256 && iscntrl(c)) { 995 (void) wprintw(win, "%s (control character)", unctrl(c)); 996 } else { 997 wchar_t c2 = c; 998 waddnwstr(win, &c2, 1); 999 (void) wprintw(win, " = %#x (printable character)", c); 1000 } 1001 } 1002 wgetch_wrap(win, first_y); 1003 } 1004 } 1005 1006 wtimeout(win, -1); 1007} 1008 1009static void 1010get_wch_test(void) 1011{ 1012 int delay = begin_getch_test(); 1013 wget_wch_test(0, stdscr, delay); 1014 finish_getch_test(); 1015} 1016#endif 1017 1018/**************************************************************************** 1019 * 1020 * Character attributes test 1021 * 1022 ****************************************************************************/ 1023 1024#define MAX_ATTRSTRING 31 1025#define LEN_ATTRSTRING 26 1026 1027static char attr_test_string[MAX_ATTRSTRING + 1]; 1028 1029static void 1030attr_legend(WINDOW *helpwin) 1031{ 1032 int row = 1; 1033 int col = 1; 1034 1035 mvwprintw(helpwin, row++, col, 1036 "q or ESC to exit."); 1037 mvwprintw(helpwin, row++, col, 1038 "^L repaints."); 1039 ++row; 1040 mvwprintw(helpwin, row++, col, 1041 "Modify the test strings:"); 1042 mvwprintw(helpwin, row++, col, 1043 " A digit sets gaps on each side of displayed attributes"); 1044 mvwprintw(helpwin, row++, col, 1045 " </> shifts the text left/right. "); 1046 ++row; 1047 mvwprintw(helpwin, row++, col, 1048 "Toggles:"); 1049 if (has_colors()) { 1050 mvwprintw(helpwin, row++, col, 1051 " f/F/b/F toggle foreground/background background color"); 1052 mvwprintw(helpwin, row++, col, 1053 " t/T toggle text/background color attribute"); 1054 } 1055 mvwprintw(helpwin, row++, col, 1056 " a/A toggle ACS (alternate character set) mapping"); 1057 mvwprintw(helpwin, row++, col, 1058 " v/V toggle video attribute to combine with each line"); 1059} 1060 1061static void 1062show_color_attr(int fg, int bg, int tx) 1063{ 1064 if (has_colors()) { 1065 printw(" Colors (fg %d, bg %d", fg, bg); 1066 if (tx >= 0) 1067 printw(", text %d", tx); 1068 printw("),"); 1069 } 1070} 1071 1072static bool 1073cycle_color_attr(int ch, int *fg, int *bg, int *tx) 1074{ 1075 bool error = FALSE; 1076 1077 if (has_colors()) { 1078 switch (ch) { 1079 case 'f': 1080 *fg = (*fg + 1); 1081 break; 1082 case 'F': 1083 *fg = (*fg - 1); 1084 break; 1085 case 'b': 1086 *bg = (*bg + 1); 1087 break; 1088 case 'B': 1089 *bg = (*bg - 1); 1090 break; 1091 case 't': 1092 *tx = (*tx + 1); 1093 break; 1094 case 'T': 1095 *tx = (*tx - 1); 1096 break; 1097 default: 1098 beep(); 1099 error = TRUE; 1100 break; 1101 } 1102 if (*fg >= COLORS) 1103 *fg = min_colors; 1104 if (*fg < min_colors) 1105 *fg = COLORS - 1; 1106 if (*bg >= COLORS) 1107 *bg = min_colors; 1108 if (*bg < min_colors) 1109 *bg = COLORS - 1; 1110 if (*tx >= COLORS) 1111 *tx = -1; 1112 if (*tx < -1) 1113 *tx = COLORS - 1; 1114 } else { 1115 beep(); 1116 error = TRUE; 1117 } 1118 return error; 1119} 1120 1121static void 1122adjust_attr_string(int adjust) 1123{ 1124 int first = ((int) UChar(attr_test_string[0])) + adjust; 1125 int last = first + LEN_ATTRSTRING; 1126 1127 if (first >= ' ' && last <= '~') { /* 32..126 */ 1128 int j, k; 1129 for (j = 0, k = first; j < MAX_ATTRSTRING && k <= last; ++j, ++k) { 1130 attr_test_string[j] = k; 1131 if (((k + 1 - first) % 5) == 0) { 1132 ++j; 1133 if (j < MAX_ATTRSTRING) 1134 attr_test_string[j] = ' '; 1135 } 1136 } 1137 while (j < MAX_ATTRSTRING) 1138 attr_test_string[j++] = ' '; 1139 attr_test_string[j] = '\0'; 1140 } else { 1141 beep(); 1142 } 1143} 1144 1145static void 1146init_attr_string(void) 1147{ 1148 attr_test_string[0] = 'a'; 1149 adjust_attr_string(0); 1150} 1151 1152static int 1153show_attr(int row, int skip, bool arrow, chtype attr, const char *name) 1154{ 1155 int ncv = tigetnum("ncv"); 1156 chtype test = attr & (chtype) (~A_ALTCHARSET); 1157 1158 if (arrow) 1159 mvprintw(row, 5, "-->"); 1160 mvprintw(row, 8, "%s mode:", name); 1161 mvprintw(row, 24, "|"); 1162 if (skip) 1163 printw("%*s", skip, " "); 1164 /* 1165 * Just for testing, write text using the alternate character set one 1166 * character at a time (to pass its rendition directly), and use the 1167 * string operation for the other attributes. 1168 */ 1169 if (attr & A_ALTCHARSET) { 1170 const char *s; 1171 chtype ch; 1172 1173 for (s = attr_test_string; *s != '\0'; ++s) { 1174 ch = UChar(*s); 1175 addch(ch | attr); 1176 } 1177 } else { 1178 attrset(attr); 1179 addstr(attr_test_string); 1180 attroff(attr); 1181 } 1182 if (skip) 1183 printw("%*s", skip, " "); 1184 printw("|"); 1185 if (test != A_NORMAL) { 1186 if (!(termattrs() & test)) { 1187 printw(" (N/A)"); 1188 } else { 1189 if (ncv > 0 && (getbkgd(stdscr) & A_COLOR)) { 1190 static const chtype table[] = 1191 { 1192 A_STANDOUT, 1193 A_UNDERLINE, 1194 A_REVERSE, 1195 A_BLINK, 1196 A_DIM, 1197 A_BOLD, 1198 A_INVIS, 1199 A_PROTECT, 1200 A_ALTCHARSET 1201 }; 1202 unsigned n; 1203 bool found = FALSE; 1204 for (n = 0; n < SIZEOF(table); n++) { 1205 if ((table[n] & attr) != 0 1206 && ((1 << n) & ncv) != 0) { 1207 found = TRUE; 1208 break; 1209 } 1210 } 1211 if (found) 1212 printw(" (NCV)"); 1213 } 1214 if ((termattrs() & test) != test) 1215 printw(" (Part)"); 1216 } 1217 } 1218 return row + 2; 1219} 1220/* *INDENT-OFF* */ 1221static const struct { 1222 attr_t attr; 1223 NCURSES_CONST char * name; 1224} attrs_to_test[] = { 1225 { A_STANDOUT, "STANDOUT" }, 1226 { A_REVERSE, "REVERSE" }, 1227 { A_BOLD, "BOLD" }, 1228 { A_UNDERLINE, "UNDERLINE" }, 1229 { A_DIM, "DIM" }, 1230 { A_BLINK, "BLINK" }, 1231 { A_PROTECT, "PROTECT" }, 1232 { A_INVIS, "INVISIBLE" }, 1233 { A_NORMAL, "NORMAL" }, 1234}; 1235/* *INDENT-ON* */ 1236 1237static bool 1238attr_getc(int *skip, int *fg, int *bg, int *tx, int *ac, unsigned *kc) 1239{ 1240 bool result = TRUE; 1241 bool error = FALSE; 1242 WINDOW *helpwin; 1243 1244 do { 1245 int ch = Getchar(); 1246 1247 error = FALSE; 1248 if (ch < 256 && isdigit(ch)) { 1249 *skip = (ch - '0'); 1250 } else { 1251 switch (ch) { 1252 case CTRL('L'): 1253 Repaint(); 1254 break; 1255 case '?': 1256 if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) { 1257 box(helpwin, 0, 0); 1258 attr_legend(helpwin); 1259 wGetchar(helpwin); 1260 delwin(helpwin); 1261 } 1262 break; 1263 case 'a': 1264 *ac = 0; 1265 break; 1266 case 'A': 1267 *ac = A_ALTCHARSET; 1268 break; 1269 case 'v': 1270 if (*kc == 0) 1271 *kc = SIZEOF(attrs_to_test) - 1; 1272 else 1273 *kc -= 1; 1274 break; 1275 case 'V': 1276 *kc += 1; 1277 if (*kc >= SIZEOF(attrs_to_test)) 1278 *kc = 0; 1279 break; 1280 case '<': 1281 adjust_attr_string(-1); 1282 break; 1283 case '>': 1284 adjust_attr_string(1); 1285 break; 1286 case 'q': 1287 case ESCAPE: 1288 result = FALSE; 1289 break; 1290 default: 1291 error = cycle_color_attr(ch, fg, bg, tx); 1292 break; 1293 } 1294 } 1295 } while (error); 1296 return result; 1297} 1298 1299static void 1300attr_test(void) 1301/* test text attributes */ 1302{ 1303 int n; 1304 int skip = tigetnum("xmc"); 1305 int fg = COLOR_BLACK; /* color pair 0 is special */ 1306 int bg = COLOR_BLACK; 1307 int tx = -1; 1308 int ac = 0; 1309 unsigned j, k; 1310 1311 if (skip < 0) 1312 skip = 0; 1313 1314 n = skip; /* make it easy */ 1315 k = SIZEOF(attrs_to_test) - 1; 1316 init_attr_string(); 1317 1318 do { 1319 int row = 2; 1320 chtype normal = A_NORMAL | BLANK; 1321 chtype extras = ac; 1322 1323 if (has_colors()) { 1324 int pair = (fg != COLOR_BLACK || bg != COLOR_BLACK); 1325 if (pair != 0) { 1326 pair = 1; 1327 if (init_pair(pair, fg, bg) == ERR) { 1328 beep(); 1329 } else { 1330 normal |= COLOR_PAIR(pair); 1331 } 1332 } 1333 if (tx >= 0) { 1334 pair = 2; 1335 if (init_pair(pair, tx, bg) == ERR) { 1336 beep(); 1337 } else { 1338 extras |= COLOR_PAIR(pair); 1339 } 1340 } 1341 } 1342 bkgd(normal); 1343 bkgdset(normal); 1344 erase(); 1345 1346 box(stdscr, 0, 0); 1347 mvaddstr(0, 20, "Character attribute test display"); 1348 1349 for (j = 0; j < SIZEOF(attrs_to_test); ++j) { 1350 row = show_attr(row, n, j == k, 1351 extras | 1352 attrs_to_test[j].attr | 1353 attrs_to_test[k].attr, 1354 attrs_to_test[j].name); 1355 } 1356 1357 mvprintw(row, 8, 1358 "This terminal does %shave the magic-cookie glitch", 1359 tigetnum("xmc") > -1 ? "" : "not "); 1360 mvprintw(row + 1, 8, "Enter '?' for help."); 1361 show_color_attr(fg, bg, tx); 1362 printw(" ACS (%d)", ac != 0); 1363 1364 refresh(); 1365 } while (attr_getc(&n, &fg, &bg, &tx, &ac, &k)); 1366 1367 bkgdset(A_NORMAL | BLANK); 1368 erase(); 1369 endwin(); 1370} 1371 1372#if USE_WIDEC_SUPPORT 1373static wchar_t wide_attr_test_string[MAX_ATTRSTRING + 1]; 1374 1375static void 1376wide_adjust_attr_string(int adjust) 1377{ 1378 int first = ((int) UChar(wide_attr_test_string[0])) + adjust; 1379 int last = first + LEN_ATTRSTRING; 1380 1381 if (first >= ' ' && last <= '~') { /* 32..126 */ 1382 int j, k; 1383 for (j = 0, k = first; j < MAX_ATTRSTRING && k <= last; ++j, ++k) { 1384 wide_attr_test_string[j] = k; 1385 if (((k + 1 - first) % 5) == 0) { 1386 ++j; 1387 if (j < MAX_ATTRSTRING) 1388 wide_attr_test_string[j] = ' '; 1389 } 1390 } 1391 while (j < MAX_ATTRSTRING) 1392 wide_attr_test_string[j++] = ' '; 1393 wide_attr_test_string[j] = '\0'; 1394 } else { 1395 beep(); 1396 } 1397} 1398 1399static void 1400wide_init_attr_string(void) 1401{ 1402 wide_attr_test_string[0] = 'a'; 1403 wide_adjust_attr_string(0); 1404} 1405 1406static void 1407set_wide_background(short pair) 1408{ 1409 cchar_t normal; 1410 wchar_t blank[2]; 1411 1412 blank[0] = ' '; 1413 blank[1] = 0; 1414 setcchar(&normal, blank, A_NORMAL, pair, 0); 1415 bkgrnd(&normal); 1416 bkgrndset(&normal); 1417} 1418 1419static attr_t 1420get_wide_background(void) 1421{ 1422 attr_t result = A_NORMAL; 1423 attr_t attr; 1424 cchar_t ch; 1425 short pair; 1426 wchar_t wch; 1427 1428 if (getbkgrnd(&ch) != ERR) { 1429 if (getcchar(&ch, &wch, &attr, &pair, 0) != ERR) { 1430 result = attr; 1431 } 1432 } 1433 return result; 1434} 1435 1436static int 1437wide_show_attr(int row, int skip, bool arrow, chtype attr, short pair, const char *name) 1438{ 1439 int ncv = tigetnum("ncv"); 1440 chtype test = attr & ~WA_ALTCHARSET; 1441 1442 if (arrow) 1443 mvprintw(row, 5, "-->"); 1444 mvprintw(row, 8, "%s mode:", name); 1445 mvprintw(row, 24, "|"); 1446 if (skip) 1447 printw("%*s", skip, " "); 1448 1449 /* 1450 * Just for testing, write text using the alternate character set one 1451 * character at a time (to pass its rendition directly), and use the 1452 * string operation for the other attributes. 1453 */ 1454 if (attr & WA_ALTCHARSET) { 1455 const wchar_t *s; 1456 cchar_t ch; 1457 1458 for (s = wide_attr_test_string; *s != L'\0'; ++s) { 1459 wchar_t fill[2]; 1460 fill[0] = *s; 1461 fill[1] = L'\0'; 1462 setcchar(&ch, fill, attr, pair, 0); 1463 add_wch(&ch); 1464 } 1465 } else { 1466 attr_t old_attr; 1467 short old_pair; 1468 1469 attr_get(&old_attr, &old_pair, 0); 1470 attr_set(attr, pair, 0); 1471 addwstr(wide_attr_test_string); 1472 attr_set(old_attr, old_pair, 0); 1473 } 1474 if (skip) 1475 printw("%*s", skip, " "); 1476 printw("|"); 1477 if (test != A_NORMAL) { 1478 if (!(term_attrs() & test)) { 1479 printw(" (N/A)"); 1480 } else { 1481 if (ncv > 0 && (get_wide_background() & A_COLOR)) { 1482 static const attr_t table[] = 1483 { 1484 WA_STANDOUT, 1485 WA_UNDERLINE, 1486 WA_REVERSE, 1487 WA_BLINK, 1488 WA_DIM, 1489 WA_BOLD, 1490 WA_INVIS, 1491 WA_PROTECT, 1492 WA_ALTCHARSET 1493 }; 1494 unsigned n; 1495 bool found = FALSE; 1496 for (n = 0; n < SIZEOF(table); n++) { 1497 if ((table[n] & attr) != 0 1498 && ((1 << n) & ncv) != 0) { 1499 found = TRUE; 1500 break; 1501 } 1502 } 1503 if (found) 1504 printw(" (NCV)"); 1505 } 1506 if ((term_attrs() & test) != test) 1507 printw(" (Part)"); 1508 } 1509 } 1510 return row + 2; 1511} 1512 1513static bool 1514wide_attr_getc(int *skip, int *fg, int *bg, int *tx, int *ac, unsigned *kc) 1515{ 1516 bool result = TRUE; 1517 bool error = FALSE; 1518 WINDOW *helpwin; 1519 1520 do { 1521 int ch = Getchar(); 1522 1523 error = FALSE; 1524 if (ch < 256 && isdigit(ch)) { 1525 *skip = (ch - '0'); 1526 } else { 1527 switch (ch) { 1528 case CTRL('L'): 1529 Repaint(); 1530 break; 1531 case '?': 1532 if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) { 1533 box_set(helpwin, 0, 0); 1534 attr_legend(helpwin); 1535 wGetchar(helpwin); 1536 delwin(helpwin); 1537 } 1538 break; 1539 case 'a': 1540 *ac = 0; 1541 break; 1542 case 'A': 1543 *ac = A_ALTCHARSET; 1544 break; 1545 case 'v': 1546 if (*kc == 0) 1547 *kc = SIZEOF(attrs_to_test) - 1; 1548 else 1549 *kc -= 1; 1550 break; 1551 case 'V': 1552 *kc += 1; 1553 if (*kc >= SIZEOF(attrs_to_test)) 1554 *kc = 0; 1555 break; 1556 case '<': 1557 wide_adjust_attr_string(-1); 1558 break; 1559 case '>': 1560 wide_adjust_attr_string(1); 1561 break; 1562 case 'q': 1563 case ESCAPE: 1564 result = FALSE; 1565 break; 1566 default: 1567 error = cycle_color_attr(ch, fg, bg, tx); 1568 break; 1569 } 1570 } 1571 } while (error); 1572 return result; 1573} 1574 1575static void 1576wide_attr_test(void) 1577/* test text attributes using wide-character calls */ 1578{ 1579 int n; 1580 int skip = tigetnum("xmc"); 1581 int fg = COLOR_BLACK; /* color pair 0 is special */ 1582 int bg = COLOR_BLACK; 1583 int tx = -1; 1584 int ac = 0; 1585 unsigned j, k; 1586 1587 if (skip < 0) 1588 skip = 0; 1589 1590 n = skip; /* make it easy */ 1591 k = SIZEOF(attrs_to_test) - 1; 1592 wide_init_attr_string(); 1593 1594 do { 1595 int row = 2; 1596 short pair = 0; 1597 short extras = 0; 1598 1599 if (has_colors()) { 1600 pair = (fg != COLOR_BLACK || bg != COLOR_BLACK); 1601 if (pair != 0) { 1602 pair = 1; 1603 if (init_pair(pair, fg, bg) == ERR) { 1604 beep(); 1605 } 1606 } 1607 extras = pair; 1608 if (tx >= 0) { 1609 extras = 2; 1610 if (init_pair(extras, tx, bg) == ERR) { 1611 beep(); 1612 } 1613 } 1614 } 1615 set_wide_background(pair); 1616 erase(); 1617 1618 box_set(stdscr, 0, 0); 1619 mvaddstr(0, 20, "Character attribute test display"); 1620 1621 for (j = 0; j < SIZEOF(attrs_to_test); ++j) { 1622 row = wide_show_attr(row, n, j == k, 1623 ac | 1624 attrs_to_test[j].attr | 1625 attrs_to_test[k].attr, 1626 extras, 1627 attrs_to_test[j].name); 1628 } 1629 1630 mvprintw(row, 8, 1631 "This terminal does %shave the magic-cookie glitch", 1632 tigetnum("xmc") > -1 ? "" : "not "); 1633 mvprintw(row + 1, 8, "Enter '?' for help."); 1634 show_color_attr(fg, bg, tx); 1635 printw(" ACS (%d)", ac != 0); 1636 1637 refresh(); 1638 } while (wide_attr_getc(&n, &fg, &bg, &tx, &ac, &k)); 1639 1640 set_wide_background(0); 1641 erase(); 1642 endwin(); 1643} 1644#endif 1645 1646/**************************************************************************** 1647 * 1648 * Color support tests 1649 * 1650 ****************************************************************************/ 1651 1652static NCURSES_CONST char *the_color_names[] = 1653{ 1654 "black", 1655 "red", 1656 "green", 1657 "yellow", 1658 "blue", 1659 "magenta", 1660 "cyan", 1661 "white", 1662 "BLACK", 1663 "RED", 1664 "GREEN", 1665 "YELLOW", 1666 "BLUE", 1667 "MAGENTA", 1668 "CYAN", 1669 "WHITE" 1670}; 1671 1672static void 1673show_color_name(int y, int x, int color, bool wide) 1674{ 1675 if (move(y, x) != ERR) { 1676 char temp[80]; 1677 int width = 8; 1678 1679 if (wide) { 1680 sprintf(temp, "%02d", color); 1681 width = 4; 1682 } else if (color >= 8) { 1683 sprintf(temp, "[%02d]", color); 1684 } else { 1685 strcpy(temp, the_color_names[color]); 1686 } 1687 printw("%-*.*s", width, width, temp); 1688 } 1689} 1690 1691static void 1692color_legend(WINDOW *helpwin) 1693{ 1694 int row = 1; 1695 int col = 1; 1696 1697 mvwprintw(helpwin, row++, col, 1698 "q or ESC to exit."); 1699 ++row; 1700 mvwprintw(helpwin, row++, col, 1701 "Use up/down arrow to scroll through the display if it is"); 1702 mvwprintw(helpwin, row++, col, 1703 "longer than one screen. Control/N and Control/P can be used"); 1704 mvwprintw(helpwin, row++, col, 1705 "in place up up/down arrow. Use pageup/pagedown to scroll a"); 1706 mvwprintw(helpwin, row++, col, 1707 "full screen; control/B and control/F can be used here."); 1708 ++row; 1709 mvwprintw(helpwin, row++, col, 1710 "Toggles:"); 1711 mvwprintw(helpwin, row++, col, 1712 " b/B toggle bold off/on"); 1713 mvwprintw(helpwin, row++, col, 1714 " n/N toggle text/number on/off"); 1715 mvwprintw(helpwin, row++, col, 1716 " w/W toggle width between 8/16 colors"); 1717} 1718 1719#define set_color_test(name, value) if (name != value) { name = value; base_row = 0; } 1720 1721/* generate a color test pattern */ 1722static void 1723color_test(void) 1724{ 1725 int c; 1726 int i; 1727 int top = 0, width; 1728 int base_row = 0; 1729 int grid_top = top + 3; 1730 int page_size = (LINES - grid_top); 1731 int pairs_max = PAIR_NUMBER(A_COLOR) + 1; 1732 int row_limit; 1733 int per_row; 1734 char numbered[80]; 1735 const char *hello; 1736 bool done = FALSE; 1737 bool opt_bold = FALSE; 1738 bool opt_wide = FALSE; 1739 bool opt_nums = FALSE; 1740 WINDOW *helpwin; 1741 1742 if (pairs_max > COLOR_PAIRS) 1743 pairs_max = COLOR_PAIRS; 1744 1745 while (!done) { 1746 int shown = 0; 1747 1748 /* this assumes an 80-column line */ 1749 if (opt_wide) { 1750 width = 4; 1751 hello = "Test"; 1752 per_row = (COLORS > 8) ? 16 : 8; 1753 } else { 1754 width = 8; 1755 hello = "Hello"; 1756 per_row = 8; 1757 } 1758 1759 row_limit = (pairs_max + per_row - 1) / per_row; 1760 1761 move(0, 0); 1762 (void) printw("There are %d color pairs and %d colors\n", 1763 pairs_max, COLORS); 1764 1765 clrtobot(); 1766 (void) mvprintw(top + 1, 0, 1767 "%dx%d matrix of foreground/background colors, bold *%s*\n", 1768 row_limit, 1769 per_row, 1770 opt_bold ? "on" : "off"); 1771 1772 /* show color names/numbers across the top */ 1773 for (i = 0; i < per_row; i++) 1774 show_color_name(top + 2, (i + 1) * width, i, opt_wide); 1775 1776 /* show a grid of colors, with color names/ numbers on the left */ 1777 for (i = (base_row * per_row); i < pairs_max; i++) { 1778 int row = grid_top + (i / per_row) - base_row; 1779 int col = (i % per_row + 1) * width; 1780 int pair = i; 1781 1782 if (row >= 0 && move(row, col) != ERR) { 1783 init_pair(pair, i % COLORS, i / COLORS); 1784 attron((attr_t) COLOR_PAIR(pair)); 1785 if (opt_bold) 1786 attron((attr_t) A_BOLD); 1787 1788 if (opt_nums) { 1789 sprintf(numbered, "{%02X}", i); 1790 hello = numbered; 1791 } 1792 printw("%-*.*s", width, width, hello); 1793 attrset(A_NORMAL); 1794 1795 if ((i % per_row) == 0 && (i % COLORS) == 0) { 1796 show_color_name(row, 0, i / COLORS, opt_wide); 1797 } 1798 ++shown; 1799 } else if (shown) { 1800 break; 1801 } 1802 } 1803 1804 switch (c = wGetchar(stdscr)) { 1805 case 'b': 1806 opt_bold = FALSE; 1807 break; 1808 case 'B': 1809 opt_bold = TRUE; 1810 break; 1811 case 'n': 1812 opt_nums = FALSE; 1813 break; 1814 case 'N': 1815 opt_nums = TRUE; 1816 break; 1817 case ESCAPE: 1818 case 'q': 1819 done = TRUE; 1820 continue; 1821 case 'w': 1822 set_color_test(opt_wide, FALSE); 1823 break; 1824 case 'W': 1825 set_color_test(opt_wide, TRUE); 1826 break; 1827 case CTRL('p'): 1828 case KEY_UP: 1829 if (base_row <= 0) { 1830 beep(); 1831 } else { 1832 base_row -= 1; 1833 } 1834 break; 1835 case CTRL('n'): 1836 case KEY_DOWN: 1837 if (base_row + page_size >= row_limit) { 1838 beep(); 1839 } else { 1840 base_row += 1; 1841 } 1842 break; 1843 case CTRL('b'): 1844 case KEY_PREVIOUS: 1845 case KEY_PPAGE: 1846 if (base_row <= 0) { 1847 beep(); 1848 } else { 1849 base_row -= (page_size - 1); 1850 if (base_row < 0) 1851 base_row = 0; 1852 } 1853 break; 1854 case CTRL('f'): 1855 case KEY_NEXT: 1856 case KEY_NPAGE: 1857 if (base_row + page_size >= row_limit) { 1858 beep(); 1859 } else { 1860 base_row += page_size - 1; 1861 if (base_row + page_size >= row_limit) { 1862 base_row = row_limit - page_size - 1; 1863 } 1864 } 1865 break; 1866 case '?': 1867 if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) { 1868 box(helpwin, 0, 0); 1869 color_legend(helpwin); 1870 wGetchar(helpwin); 1871 delwin(helpwin); 1872 } 1873 break; 1874 default: 1875 beep(); 1876 continue; 1877 } 1878 } 1879 1880 erase(); 1881 endwin(); 1882} 1883 1884#if USE_WIDEC_SUPPORT 1885/* generate a color test pattern */ 1886static void 1887wide_color_test(void) 1888{ 1889 int c; 1890 int i; 1891 int top = 0, width; 1892 int base_row = 0; 1893 int grid_top = top + 3; 1894 int page_size = (LINES - grid_top); 1895 int pairs_max = COLOR_PAIRS; 1896 int row_limit; 1897 int per_row; 1898 char numbered[80]; 1899 const char *hello; 1900 bool done = FALSE; 1901 bool opt_bold = FALSE; 1902 bool opt_wide = FALSE; 1903 bool opt_nums = FALSE; 1904 WINDOW *helpwin; 1905 1906 while (!done) { 1907 int shown = 0; 1908 1909 /* this assumes an 80-column line */ 1910 if (opt_wide) { 1911 width = 4; 1912 hello = "Test"; 1913 per_row = (COLORS > 8) ? 16 : 8; 1914 } else { 1915 width = 8; 1916 hello = "Hello"; 1917 per_row = 8; 1918 } 1919 1920 row_limit = (pairs_max + per_row - 1) / per_row; 1921 1922 move(0, 0); 1923 (void) printw("There are %d color pairs and %d colors\n", 1924 pairs_max, COLORS); 1925 1926 clrtobot(); 1927 (void) mvprintw(top + 1, 0, 1928 "%dx%d matrix of foreground/background colors, bold *%s*\n", 1929 row_limit, 1930 per_row, 1931 opt_bold ? "on" : "off"); 1932 1933 /* show color names/numbers across the top */ 1934 for (i = 0; i < per_row; i++) 1935 show_color_name(top + 2, (i + 1) * width, i, opt_wide); 1936 1937 /* show a grid of colors, with color names/ numbers on the left */ 1938 for (i = (base_row * per_row); i < pairs_max; i++) { 1939 int row = grid_top + (i / per_row) - base_row; 1940 int col = (i % per_row + 1) * width; 1941 int pair = i; 1942 1943 if (row >= 0 && move(row, col) != ERR) { 1944 init_pair(pair, i % COLORS, i / COLORS); 1945 color_set(pair, NULL); 1946 if (opt_bold) 1947 attr_on((attr_t) A_BOLD, NULL); 1948 1949 if (opt_nums) { 1950 sprintf(numbered, "{%02X}", i); 1951 hello = numbered; 1952 } 1953 printw("%-*.*s", width, width, hello); 1954 attr_set(A_NORMAL, 0, NULL); 1955 1956 if ((i % per_row) == 0 && (i % COLORS) == 0) { 1957 show_color_name(row, 0, i / COLORS, opt_wide); 1958 } 1959 ++shown; 1960 } else if (shown) { 1961 break; 1962 } 1963 } 1964 1965 switch (c = wGetchar(stdscr)) { 1966 case 'b': 1967 opt_bold = FALSE; 1968 break; 1969 case 'B': 1970 opt_bold = TRUE; 1971 break; 1972 case 'n': 1973 opt_nums = FALSE; 1974 break; 1975 case 'N': 1976 opt_nums = TRUE; 1977 break; 1978 case ESCAPE: 1979 case 'q': 1980 done = TRUE; 1981 continue; 1982 case 'w': 1983 set_color_test(opt_wide, FALSE); 1984 break; 1985 case 'W': 1986 set_color_test(opt_wide, TRUE); 1987 break; 1988 case CTRL('p'): 1989 case KEY_UP: 1990 if (base_row <= 0) { 1991 beep(); 1992 } else { 1993 base_row -= 1; 1994 } 1995 break; 1996 case CTRL('n'): 1997 case KEY_DOWN: 1998 if (base_row + page_size >= row_limit) { 1999 beep(); 2000 } else { 2001 base_row += 1; 2002 } 2003 break; 2004 case CTRL('b'): 2005 case KEY_PREVIOUS: 2006 case KEY_PPAGE: 2007 if (base_row <= 0) { 2008 beep(); 2009 } else { 2010 base_row -= (page_size - 1); 2011 if (base_row < 0) 2012 base_row = 0; 2013 } 2014 break; 2015 case CTRL('f'): 2016 case KEY_NEXT: 2017 case KEY_NPAGE: 2018 if (base_row + page_size >= row_limit) { 2019 beep(); 2020 } else { 2021 base_row += page_size - 1; 2022 if (base_row + page_size >= row_limit) { 2023 base_row = row_limit - page_size - 1; 2024 } 2025 } 2026 break; 2027 case '?': 2028 if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) { 2029 box(helpwin, 0, 0); 2030 color_legend(helpwin); 2031 wGetchar(helpwin); 2032 delwin(helpwin); 2033 } 2034 break; 2035 default: 2036 beep(); 2037 continue; 2038 } 2039 } 2040 2041 erase(); 2042 endwin(); 2043} 2044#endif /* USE_WIDEC_SUPPORT */ 2045 2046static void 2047change_color(int current, int field, int value, int usebase) 2048{ 2049 short red, green, blue; 2050 2051 if (usebase) 2052 color_content(current, &red, &green, &blue); 2053 else 2054 red = green = blue = 0; 2055 2056 switch (field) { 2057 case 0: 2058 red += value; 2059 break; 2060 case 1: 2061 green += value; 2062 break; 2063 case 2: 2064 blue += value; 2065 break; 2066 } 2067 2068 if (init_color(current, red, green, blue) == ERR) 2069 beep(); 2070} 2071 2072static void 2073init_all_colors(void) 2074{ 2075 int c; 2076 for (c = 0; c < COLORS; ++c) 2077 init_color(c, 2078 all_colors[c].red, 2079 all_colors[c].green, 2080 all_colors[c].blue); 2081} 2082 2083#define scaled_rgb(n) ((255 * (n)) / 1000) 2084 2085static void 2086color_edit(void) 2087/* display the color test pattern, without trying to edit colors */ 2088{ 2089 int i, this_c = 0, value = 0, current = 0, field = 0; 2090 int last_c; 2091 int top_color = 0; 2092 int page_size = (LINES - 6); 2093 2094 init_all_colors(); 2095 refresh(); 2096 2097 for (i = 0; i < max_colors; i++) 2098 init_pair(i, COLOR_WHITE, i); 2099 2100 mvprintw(LINES - 2, 0, "Number: %d", value); 2101 2102 do { 2103 short red, green, blue; 2104 2105 attron(A_BOLD); 2106 mvaddstr(0, 20, "Color RGB Value Editing"); 2107 attroff(A_BOLD); 2108 2109 for (i = top_color; 2110 (i - top_color < page_size) 2111 && (i < max_colors); i++) { 2112 char numeric[80]; 2113 sprintf(numeric, "[%d]", i); 2114 mvprintw(2 + i - top_color, 0, "%c %-8s:", 2115 (i == current ? '>' : ' '), 2116 (i < (int) SIZEOF(the_color_names) 2117 ? the_color_names[i] : numeric)); 2118 attrset(COLOR_PAIR(i)); 2119 addstr(" "); 2120 attrset(A_NORMAL); 2121 2122 color_content(i, &red, &green, &blue); 2123 addstr(" R = "); 2124 if (current == i && field == 0) 2125 attron(A_STANDOUT); 2126 printw("%04d", red); 2127 if (current == i && field == 0) 2128 attrset(A_NORMAL); 2129 addstr(", G = "); 2130 if (current == i && field == 1) 2131 attron(A_STANDOUT); 2132 printw("%04d", green); 2133 if (current == i && field == 1) 2134 attrset(A_NORMAL); 2135 addstr(", B = "); 2136 if (current == i && field == 2) 2137 attron(A_STANDOUT); 2138 printw("%04d", blue); 2139 if (current == i && field == 2) 2140 attrset(A_NORMAL); 2141 attrset(A_NORMAL); 2142 printw(" ( %3d %3d %3d )", 2143 scaled_rgb(red), 2144 scaled_rgb(green), 2145 scaled_rgb(blue)); 2146 } 2147 2148 mvaddstr(LINES - 3, 0, 2149 "Use up/down to select a color, left/right to change fields."); 2150 mvaddstr(LINES - 2, 0, 2151 "Modify field by typing nnn=, nnn-, or nnn+. ? for help."); 2152 2153 move(2 + current - top_color, 0); 2154 2155 last_c = this_c; 2156 this_c = Getchar(); 2157 if (this_c < 256 && isdigit(this_c) && !isdigit(last_c)) 2158 value = 0; 2159 2160 switch (this_c) { 2161 case CTRL('b'): 2162 case KEY_PPAGE: 2163 if (current > 0) 2164 current -= (page_size - 1); 2165 else 2166 beep(); 2167 break; 2168 2169 case CTRL('f'): 2170 case KEY_NPAGE: 2171 if (current < (max_colors - 1)) 2172 current += (page_size - 1); 2173 else 2174 beep(); 2175 break; 2176 2177 case CTRL('p'): 2178 case KEY_UP: 2179 current = (current == 0 ? (max_colors - 1) : current - 1); 2180 break; 2181 2182 case CTRL('n'): 2183 case KEY_DOWN: 2184 current = (current == (max_colors - 1) ? 0 : current + 1); 2185 break; 2186 2187 case KEY_RIGHT: 2188 field = (field == 2 ? 0 : field + 1); 2189 break; 2190 2191 case KEY_LEFT: 2192 field = (field == 0 ? 2 : field - 1); 2193 break; 2194 2195 case '0': 2196 case '1': 2197 case '2': 2198 case '3': 2199 case '4': 2200 case '5': 2201 case '6': 2202 case '7': 2203 case '8': 2204 case '9': 2205 value = value * 10 + (this_c - '0'); 2206 break; 2207 2208 case '+': 2209 change_color(current, field, value, 1); 2210 break; 2211 2212 case '-': 2213 change_color(current, field, -value, 1); 2214 break; 2215 2216 case '=': 2217 change_color(current, field, value, 0); 2218 break; 2219 2220 case '?': 2221 erase(); 2222 P(" RGB Value Editing Help"); 2223 P(""); 2224 P("You are in the RGB value editor. Use the arrow keys to select one of"); 2225 P("the fields in one of the RGB triples of the current colors; the one"); 2226 P("currently selected will be reverse-video highlighted."); 2227 P(""); 2228 P("To change a field, enter the digits of the new value; they are echoed"); 2229 P("as entered. Finish by typing `='. The change will take effect instantly."); 2230 P("To increment or decrement a value, use the same procedure, but finish"); 2231 P("with a `+' or `-'."); 2232 P(""); 2233 P("Press 'm' to invoke the top-level menu with the current color settings."); 2234 P("To quit, do `x' or 'q'"); 2235 2236 Pause(); 2237 erase(); 2238 break; 2239 2240 case 'm': 2241 endwin(); 2242 main_menu(FALSE); 2243 refresh(); 2244 break; 2245 2246 case 'x': 2247 case 'q': 2248 break; 2249 2250 default: 2251 beep(); 2252 break; 2253 } 2254 2255 if (current < 0) 2256 current = 0; 2257 if (current >= max_colors) 2258 current = max_colors - 1; 2259 if (current < top_color) 2260 top_color = current; 2261 if (current - top_color >= page_size) 2262 top_color = current - (page_size - 1); 2263 2264 mvprintw(LINES - 1, 0, "Number: %d", value); 2265 clrtoeol(); 2266 } while 2267 (this_c != 'x' && this_c != 'q'); 2268 2269 erase(); 2270 2271 /* 2272 * ncurses does not reset each color individually when calling endwin(). 2273 */ 2274 init_all_colors(); 2275 2276 endwin(); 2277} 2278 2279/**************************************************************************** 2280 * 2281 * Soft-key label test 2282 * 2283 ****************************************************************************/ 2284 2285#define SLK_HELP 17 2286#define SLK_WORK (SLK_HELP + 3) 2287 2288static void 2289slk_help(void) 2290{ 2291 static const char *table[] = 2292 { 2293 "Available commands are:" 2294 ,"" 2295 ,"^L -- repaint this message and activate soft keys" 2296 ,"a/d -- activate/disable soft keys" 2297 ,"c -- set centered format for labels" 2298 ,"l -- set left-justified format for labels" 2299 ,"r -- set right-justified format for labels" 2300 ,"[12345678] -- set label; labels are numbered 1 through 8" 2301 ,"e -- erase stdscr (should not erase labels)" 2302 ,"s -- test scrolling of shortened screen" 2303#if HAVE_SLK_COLOR 2304 ,"F/B -- cycle through foreground/background colors" 2305#endif 2306 ,"x, q -- return to main menu" 2307 ,"" 2308 ,"Note: if activating the soft keys causes your terminal to scroll up" 2309 ,"one line, your terminal auto-scrolls when anything is written to the" 2310 ,"last screen position. The ncurses code does not yet handle this" 2311 ,"gracefully." 2312 }; 2313 unsigned j; 2314 2315 move(2, 0); 2316 for (j = 0; j < SIZEOF(table); ++j) { 2317 P(table[j]); 2318 } 2319 refresh(); 2320} 2321 2322static void 2323slk_test(void) 2324/* exercise the soft keys */ 2325{ 2326 int c, fmt = 1; 2327 char buf[9]; 2328 char *s; 2329#if HAVE_SLK_COLOR 2330 short fg = COLOR_BLACK; 2331 short bg = COLOR_WHITE; 2332 bool new_color = FALSE; 2333#endif 2334 2335 c = CTRL('l'); 2336#if HAVE_SLK_COLOR 2337 if (has_colors()) { 2338 new_color = TRUE; 2339 } 2340#endif 2341 2342 do { 2343#if HAVE_SLK_COLOR 2344 if (new_color) { 2345 init_pair(1, bg, fg); 2346 slk_color(1); 2347 new_color = FALSE; 2348 mvprintw(SLK_WORK, 0, "Colors %d/%d\n", fg, bg); 2349 refresh(); 2350 } 2351#endif 2352 move(0, 0); 2353 switch (c) { 2354 case CTRL('l'): 2355 erase(); 2356 attron(A_BOLD); 2357 mvaddstr(0, 20, "Soft Key Exerciser"); 2358 attroff(A_BOLD); 2359 2360 slk_help(); 2361 /* fall through */ 2362 2363 case 'a': 2364 slk_restore(); 2365 break; 2366 2367 case 'e': 2368 wclear(stdscr); 2369 break; 2370 2371 case 's': 2372 mvprintw(SLK_WORK, 0, "Press Q to stop the scrolling-test: "); 2373 while ((c = Getchar()) != 'Q' && (c != ERR)) 2374 addch((chtype) c); 2375 break; 2376 2377 case 'd': 2378 slk_clear(); 2379 break; 2380 2381 case 'l': 2382 fmt = 0; 2383 break; 2384 2385 case 'c': 2386 fmt = 1; 2387 break; 2388 2389 case 'r': 2390 fmt = 2; 2391 break; 2392 2393 case '1': 2394 case '2': 2395 case '3': 2396 case '4': 2397 case '5': 2398 case '6': 2399 case '7': 2400 case '8': 2401 (void) mvaddstr(SLK_WORK, 0, "Please enter the label value: "); 2402 strcpy(buf, ""); 2403 if ((s = slk_label(c - '0')) != 0) { 2404 strncpy(buf, s, 8); 2405 } 2406 wGetstring(stdscr, buf, 8); 2407 slk_set((c - '0'), buf, fmt); 2408 slk_refresh(); 2409 move(SLK_WORK, 0); 2410 clrtobot(); 2411 break; 2412 2413 case 'x': 2414 case 'q': 2415 goto done; 2416 2417#if HAVE_SLK_COLOR 2418 case 'F': 2419 if (has_colors()) { 2420 fg = (fg + 1) % COLORS; 2421 new_color = TRUE; 2422 } 2423 break; 2424 case 'B': 2425 if (has_colors()) { 2426 bg = (bg + 1) % COLORS; 2427 new_color = TRUE; 2428 } 2429 break; 2430#endif 2431 2432 default: 2433 beep(); 2434 } 2435 } while 2436 ((c = Getchar()) != EOF); 2437 2438 done: 2439 erase(); 2440 endwin(); 2441} 2442 2443#if USE_WIDEC_SUPPORT 2444#define SLKLEN 8 2445static void 2446wide_slk_test(void) 2447/* exercise the soft keys */ 2448{ 2449 int c, fmt = 1; 2450 wchar_t buf[SLKLEN + 1]; 2451 char *s; 2452 short fg = COLOR_BLACK; 2453 short bg = COLOR_WHITE; 2454 bool new_color = FALSE; 2455 2456 c = CTRL('l'); 2457 if (has_colors()) { 2458 new_color = TRUE; 2459 } 2460 do { 2461 if (new_color) { 2462 init_pair(1, bg, fg); 2463 slk_color(1); 2464 new_color = FALSE; 2465 mvprintw(SLK_WORK, 0, "Colors %d/%d\n", fg, bg); 2466 refresh(); 2467 } 2468 move(0, 0); 2469 switch (c) { 2470 case CTRL('l'): 2471 erase(); 2472 attr_on(WA_BOLD, NULL); 2473 mvaddstr(0, 20, "Soft Key Exerciser"); 2474 attr_off(WA_BOLD, NULL); 2475 2476 slk_help(); 2477 /* fall through */ 2478 2479 case 'a': 2480 slk_restore(); 2481 break; 2482 2483 case 'e': 2484 wclear(stdscr); 2485 break; 2486 2487 case 's': 2488 mvprintw(SLK_WORK, 0, "Press Q to stop the scrolling-test: "); 2489 while ((c = Getchar()) != 'Q' && (c != ERR)) 2490 addch((chtype) c); 2491 break; 2492 2493 case 'd': 2494 slk_clear(); 2495 break; 2496 2497 case 'l': 2498 fmt = 0; 2499 break; 2500 2501 case 'c': 2502 fmt = 1; 2503 break; 2504 2505 case 'r': 2506 fmt = 2; 2507 break; 2508 2509 case '1': 2510 case '2': 2511 case '3': 2512 case '4': 2513 case '5': 2514 case '6': 2515 case '7': 2516 case '8': 2517 (void) mvaddstr(SLK_WORK, 0, "Please enter the label value: "); 2518 *buf = 0; 2519 if ((s = slk_label(c - '0')) != 0) { 2520 char *temp = strdup(s); 2521 size_t used = strlen(temp); 2522 size_t want = SLKLEN; 2523 size_t test; 2524 mbstate_t state; 2525 2526 buf[0] = L'\0'; 2527 while (want > 0 && used != 0) { 2528 const char *base = s; 2529 memset(&state, 0, sizeof(state)); 2530 test = mbsrtowcs(0, &base, 0, &state); 2531 if (test == (size_t) -1) { 2532 temp[--used] = 0; 2533 } else if (test > want) { 2534 temp[--used] = 0; 2535 } else { 2536 memset(&state, 0, sizeof(state)); 2537 mbsrtowcs(buf, &base, want, &state); 2538 break; 2539 } 2540 } 2541 free(temp); 2542 } 2543 wGet_wstring(stdscr, buf, SLKLEN); 2544 slk_wset((c - '0'), buf, fmt); 2545 slk_refresh(); 2546 move(SLK_WORK, 0); 2547 clrtobot(); 2548 break; 2549 2550 case 'x': 2551 case 'q': 2552 goto done; 2553 2554 case 'F': 2555 if (has_colors()) { 2556 fg = (fg + 1) % COLORS; 2557 new_color = TRUE; 2558 } 2559 break; 2560 case 'B': 2561 if (has_colors()) { 2562 bg = (bg + 1) % COLORS; 2563 new_color = TRUE; 2564 } 2565 break; 2566 2567 default: 2568 beep(); 2569 } 2570 } while 2571 ((c = Getchar()) != EOF); 2572 2573 done: 2574 erase(); 2575 endwin(); 2576} 2577#endif 2578 2579/**************************************************************************** 2580 * 2581 * Alternate character-set stuff 2582 * 2583 ****************************************************************************/ 2584 2585/* ISO 6429: codes 0x80 to 0x9f may be control characters that cause the 2586 * terminal to perform functions. The remaining codes can be graphic. 2587 */ 2588static void 2589show_upper_chars(unsigned first) 2590{ 2591 bool C1 = (first == 128); 2592 unsigned code; 2593 unsigned last = first + 31; 2594 int reply; 2595 2596 erase(); 2597 attron(A_BOLD); 2598 mvprintw(0, 20, "Display of %s Character Codes %d to %d", 2599 C1 ? "C1" : "GR", first, last); 2600 attroff(A_BOLD); 2601 refresh(); 2602 2603 for (code = first; code <= last; code++) { 2604 int row = 4 + ((code - first) % 16); 2605 int col = ((code - first) / 16) * COLS / 2; 2606 char tmp[80]; 2607 sprintf(tmp, "%3u (0x%x)", code, code); 2608 mvprintw(row, col, "%*s: ", COLS / 4, tmp); 2609 if (C1) 2610 nodelay(stdscr, TRUE); 2611 echochar(code); 2612 if (C1) { 2613 /* (yes, this _is_ crude) */ 2614 while ((reply = Getchar()) != ERR) { 2615 addch(UChar(reply)); 2616 napms(10); 2617 } 2618 nodelay(stdscr, FALSE); 2619 } 2620 } 2621} 2622 2623static void 2624show_box_chars(void) 2625{ 2626 erase(); 2627 attron(A_BOLD); 2628 mvaddstr(0, 20, "Display of the ACS Line-Drawing Set"); 2629 attroff(A_BOLD); 2630 refresh(); 2631 box(stdscr, 0, 0); 2632 /* *INDENT-OFF* */ 2633 mvhline(LINES / 2, 0, ACS_HLINE, COLS); 2634 mvvline(0, COLS / 2, ACS_VLINE, LINES); 2635 mvaddch(0, COLS / 2, ACS_TTEE); 2636 mvaddch(LINES / 2, COLS / 2, ACS_PLUS); 2637 mvaddch(LINES - 1, COLS / 2, ACS_BTEE); 2638 mvaddch(LINES / 2, 0, ACS_LTEE); 2639 mvaddch(LINES / 2, COLS - 1, ACS_RTEE); 2640 /* *INDENT-ON* */ 2641 2642} 2643 2644static int 2645show_1_acs(int n, const char *name, chtype code) 2646{ 2647 const int height = 16; 2648 int row = 4 + (n % height); 2649 int col = (n / height) * COLS / 2; 2650 mvprintw(row, col, "%*s : ", COLS / 4, name); 2651 addch(code); 2652 return n + 1; 2653} 2654 2655static void 2656show_acs_chars(void) 2657/* display the ACS character set */ 2658{ 2659 int n; 2660 2661#define BOTH(name) #name, name 2662 2663 erase(); 2664 attron(A_BOLD); 2665 mvaddstr(0, 20, "Display of the ACS Character Set"); 2666 attroff(A_BOLD); 2667 refresh(); 2668 2669 n = show_1_acs(0, BOTH(ACS_ULCORNER)); 2670 n = show_1_acs(n, BOTH(ACS_URCORNER)); 2671 n = show_1_acs(n, BOTH(ACS_LLCORNER)); 2672 n = show_1_acs(n, BOTH(ACS_LRCORNER)); 2673 2674 n = show_1_acs(n, BOTH(ACS_LTEE)); 2675 n = show_1_acs(n, BOTH(ACS_RTEE)); 2676 n = show_1_acs(n, BOTH(ACS_TTEE)); 2677 n = show_1_acs(n, BOTH(ACS_BTEE)); 2678 2679 n = show_1_acs(n, BOTH(ACS_HLINE)); 2680 n = show_1_acs(n, BOTH(ACS_VLINE)); 2681 2682 n = show_1_acs(n, BOTH(ACS_LARROW)); 2683 n = show_1_acs(n, BOTH(ACS_RARROW)); 2684 n = show_1_acs(n, BOTH(ACS_UARROW)); 2685 n = show_1_acs(n, BOTH(ACS_DARROW)); 2686 2687 n = show_1_acs(n, BOTH(ACS_BLOCK)); 2688 n = show_1_acs(n, BOTH(ACS_BOARD)); 2689 n = show_1_acs(n, BOTH(ACS_LANTERN)); 2690 n = show_1_acs(n, BOTH(ACS_BULLET)); 2691 n = show_1_acs(n, BOTH(ACS_CKBOARD)); 2692 n = show_1_acs(n, BOTH(ACS_DEGREE)); 2693 n = show_1_acs(n, BOTH(ACS_DIAMOND)); 2694 n = show_1_acs(n, BOTH(ACS_PLMINUS)); 2695 n = show_1_acs(n, BOTH(ACS_PLUS)); 2696 2697 n = show_1_acs(n, BOTH(ACS_GEQUAL)); 2698 n = show_1_acs(n, BOTH(ACS_NEQUAL)); 2699 n = show_1_acs(n, BOTH(ACS_LEQUAL)); 2700 2701 n = show_1_acs(n, BOTH(ACS_STERLING)); 2702 n = show_1_acs(n, BOTH(ACS_PI)); 2703 n = show_1_acs(n, BOTH(ACS_S1)); 2704 n = show_1_acs(n, BOTH(ACS_S3)); 2705 n = show_1_acs(n, BOTH(ACS_S7)); 2706 n = show_1_acs(n, BOTH(ACS_S9)); 2707} 2708 2709static void 2710acs_display(void) 2711{ 2712 int c = 'a'; 2713 2714 do { 2715 switch (c) { 2716 case CTRL('L'): 2717 Repaint(); 2718 break; 2719 case 'a': 2720 show_acs_chars(); 2721 break; 2722 case 'b': 2723 show_box_chars(); 2724 break; 2725 case '0': 2726 case '1': 2727 case '2': 2728 case '3': 2729 show_upper_chars((unsigned) ((c - '0') * 32 + 128)); 2730 break; 2731 } 2732 mvprintw(LINES - 3, 0, 2733 "Note: ANSI terminals may not display C1 characters."); 2734 mvprintw(LINES - 2, 0, 2735 "Select: a=ACS, b=box, 0=C1, 1,2,3=GR characters, q=quit"); 2736 refresh(); 2737 } while ((c = Getchar()) != 'x' && c != 'q'); 2738 2739 Pause(); 2740 erase(); 2741 endwin(); 2742} 2743 2744#if USE_WIDEC_SUPPORT 2745static void 2746show_upper_widechars(int first, int repeat, int space) 2747{ 2748 cchar_t temp; 2749 wchar_t code; 2750 int last = first + 31; 2751 2752 erase(); 2753 attron(A_BOLD); 2754 mvprintw(0, 20, "Display of Character Codes %d to %d", first, last); 2755 attroff(A_BOLD); 2756 2757 for (code = first; code <= last; code++) { 2758 int row = 4 + ((code - first) % 16); 2759 int col = ((code - first) / 16) * COLS / 2; 2760 wchar_t codes[10]; 2761 attr_t attrs = A_NORMAL; 2762 char tmp[80]; 2763 int count = repeat; 2764 2765 memset(&codes, 0, sizeof(codes)); 2766 codes[0] = code; 2767 sprintf(tmp, "%3ld (0x%lx)", (long) code, (long) code); 2768 mvprintw(row, col, "%*s: ", COLS / 4, tmp); 2769 setcchar(&temp, codes, attrs, 0, 0); 2770 do { 2771 /* 2772 * Give non-spacing characters something to combine with. If we 2773 * don't, they'll bunch up in a heap on the space after the ":". 2774 * Mark them with reverse-video to make them simpler to find on 2775 * the display. 2776 */ 2777 if (wcwidth(code) == 0) 2778 addch(space | A_REVERSE); 2779 /* 2780 * This could use add_wch(), but is done for comparison with the 2781 * normal 'f' test (and to make a test-case for echo_wchar()). 2782 * The screen will flicker because the erase() at the top of the 2783 * function is met by the builtin refresh() in echo_wchar(). 2784 */ 2785 echo_wchar(&temp); 2786 } while (--count > 0); 2787 } 2788} 2789 2790static int 2791show_1_wacs(int n, const char *name, const cchar_t *code) 2792{ 2793 const int height = 16; 2794 int row = 4 + (n % height); 2795 int col = (n / height) * COLS / 2; 2796 mvprintw(row, col, "%*s : ", COLS / 4, name); 2797 add_wchnstr(code, 1); 2798 return n + 1; 2799} 2800 2801static void 2802show_wacs_chars(void) 2803/* display the wide-ACS character set */ 2804{ 2805 int n; 2806 2807/*#define BOTH2(name) #name, &(name) */ 2808#define BOTH2(name) #name, name 2809 2810 erase(); 2811 attron(A_BOLD); 2812 mvaddstr(0, 20, "Display of the Wide-ACS Character Set"); 2813 attroff(A_BOLD); 2814 refresh(); 2815 2816 n = show_1_wacs(0, BOTH2(WACS_ULCORNER)); 2817 n = show_1_wacs(n, BOTH2(WACS_URCORNER)); 2818 n = show_1_wacs(n, BOTH2(WACS_LLCORNER)); 2819 n = show_1_wacs(n, BOTH2(WACS_LRCORNER)); 2820 2821 n = show_1_wacs(n, BOTH2(WACS_LTEE)); 2822 n = show_1_wacs(n, BOTH2(WACS_RTEE)); 2823 n = show_1_wacs(n, BOTH2(WACS_TTEE)); 2824 n = show_1_wacs(n, BOTH2(WACS_BTEE)); 2825 2826 n = show_1_wacs(n, BOTH2(WACS_HLINE)); 2827 n = show_1_wacs(n, BOTH2(WACS_VLINE)); 2828 2829 n = show_1_wacs(n, BOTH2(WACS_LARROW)); 2830 n = show_1_wacs(n, BOTH2(WACS_RARROW)); 2831 n = show_1_wacs(n, BOTH2(WACS_UARROW)); 2832 n = show_1_wacs(n, BOTH2(WACS_DARROW)); 2833 2834 n = show_1_wacs(n, BOTH2(WACS_BLOCK)); 2835 n = show_1_wacs(n, BOTH2(WACS_BOARD)); 2836 n = show_1_wacs(n, BOTH2(WACS_LANTERN)); 2837 n = show_1_wacs(n, BOTH2(WACS_BULLET)); 2838 n = show_1_wacs(n, BOTH2(WACS_CKBOARD)); 2839 n = show_1_wacs(n, BOTH2(WACS_DEGREE)); 2840 n = show_1_wacs(n, BOTH2(WACS_DIAMOND)); 2841 n = show_1_wacs(n, BOTH2(WACS_PLMINUS)); 2842 n = show_1_wacs(n, BOTH2(WACS_PLUS)); 2843 2844#ifdef CURSES_WACS_ARRAY 2845 n = show_1_wacs(n, BOTH2(WACS_GEQUAL)); 2846 n = show_1_wacs(n, BOTH2(WACS_NEQUAL)); 2847 n = show_1_wacs(n, BOTH2(WACS_LEQUAL)); 2848 2849 n = show_1_wacs(n, BOTH2(WACS_STERLING)); 2850 n = show_1_wacs(n, BOTH2(WACS_PI)); 2851 n = show_1_wacs(n, BOTH2(WACS_S1)); 2852 n = show_1_wacs(n, BOTH2(WACS_S3)); 2853 n = show_1_wacs(n, BOTH2(WACS_S7)); 2854 n = show_1_wacs(n, BOTH2(WACS_S9)); 2855#endif 2856} 2857 2858static void 2859show_wbox_chars(void) 2860{ 2861 erase(); 2862 attron(A_BOLD); 2863 mvaddstr(0, 20, "Display of the Wide-ACS Line-Drawing Set"); 2864 attroff(A_BOLD); 2865 refresh(); 2866 box_set(stdscr, 0, 0); 2867 /* *INDENT-OFF* */ 2868 mvhline_set(LINES / 2, 0, WACS_HLINE, COLS); 2869 mvvline_set(0, COLS / 2, WACS_VLINE, LINES); 2870 mvadd_wch(0, COLS / 2, WACS_TTEE); 2871 mvadd_wch(LINES / 2, COLS / 2, WACS_PLUS); 2872 mvadd_wch(LINES - 1, COLS / 2, WACS_BTEE); 2873 mvadd_wch(LINES / 2, 0, WACS_LTEE); 2874 mvadd_wch(LINES / 2, COLS - 1, WACS_RTEE); 2875 /* *INDENT-ON* */ 2876 2877} 2878 2879static int 2880show_2_wacs(int n, const char *name, const char *code) 2881{ 2882 const int height = 16; 2883 int row = 4 + (n % height); 2884 int col = (n / height) * COLS / 2; 2885 char temp[80]; 2886 2887 mvprintw(row, col, "%*s : ", COLS / 4, name); 2888 addstr(strcpy(temp, code)); 2889 return n + 1; 2890} 2891 2892static void 2893show_utf8_chars(void) 2894/* display the wide-ACS character set */ 2895{ 2896 int n; 2897 2898 erase(); 2899 attron(A_BOLD); 2900 mvaddstr(0, 20, "Display of the Wide-ACS Character Set"); 2901 attroff(A_BOLD); 2902 refresh(); 2903 /* *INDENT-OFF* */ 2904 n = show_2_wacs(0, "WACS_ULCORNER", "\342\224\214"); 2905 n = show_2_wacs(n, "WACS_URCORNER", "\342\224\220"); 2906 n = show_2_wacs(n, "WACS_LLCORNER", "\342\224\224"); 2907 n = show_2_wacs(n, "WACS_LRCORNER", "\342\224\230"); 2908 2909 n = show_2_wacs(n, "WACS_LTEE", "\342\224\234"); 2910 n = show_2_wacs(n, "WACS_RTEE", "\342\224\244"); 2911 n = show_2_wacs(n, "WACS_TTEE", "\342\224\254"); 2912 n = show_2_wacs(n, "WACS_BTEE", "\342\224\264"); 2913 2914 n = show_2_wacs(n, "WACS_HLINE", "\342\224\200"); 2915 n = show_2_wacs(n, "WACS_VLINE", "\342\224\202"); 2916 2917 n = show_2_wacs(n, "WACS_LARROW", "\342\206\220"); 2918 n = show_2_wacs(n, "WACS_RARROW", "\342\206\222"); 2919 n = show_2_wacs(n, "WACS_UARROW", "\342\206\221"); 2920 n = show_2_wacs(n, "WACS_DARROW", "\342\206\223"); 2921 2922 n = show_2_wacs(n, "WACS_BLOCK", "\342\226\256"); 2923 n = show_2_wacs(n, "WACS_BOARD", "\342\226\222"); 2924 n = show_2_wacs(n, "WACS_LANTERN", "\342\230\203"); 2925 n = show_2_wacs(n, "WACS_BULLET", "\302\267"); 2926 n = show_2_wacs(n, "WACS_CKBOARD", "\342\226\222"); 2927 n = show_2_wacs(n, "WACS_DEGREE", "\302\260"); 2928 n = show_2_wacs(n, "WACS_DIAMOND", "\342\227\206"); 2929 n = show_2_wacs(n, "WACS_PLMINUS", "\302\261"); 2930 n = show_2_wacs(n, "WACS_PLUS", "\342\224\274"); 2931 n = show_2_wacs(n, "WACS_GEQUAL", "\342\211\245"); 2932 n = show_2_wacs(n, "WACS_NEQUAL", "\342\211\240"); 2933 n = show_2_wacs(n, "WACS_LEQUAL", "\342\211\244"); 2934 2935 n = show_2_wacs(n, "WACS_STERLING", "\302\243"); 2936 n = show_2_wacs(n, "WACS_PI", "\317\200"); 2937 n = show_2_wacs(n, "WACS_S1", "\342\216\272"); 2938 n = show_2_wacs(n, "WACS_S3", "\342\216\273"); 2939 n = show_2_wacs(n, "WACS_S7", "\342\216\274"); 2940 n = show_2_wacs(n, "WACS_S9", "\342\216\275"); 2941 /* *INDENT-ON* */ 2942 2943} 2944 2945static void 2946wide_acs_display(void) 2947{ 2948 int c = 'a'; 2949 int digit = 0; 2950 int repeat = 0; 2951 int space = ' '; 2952 2953 do { 2954 switch (c) { 2955 case CTRL('L'): 2956 Repaint(); 2957 break; 2958 case 'a': 2959 show_wacs_chars(); 2960 break; 2961 case 'b': 2962 show_wbox_chars(); 2963 break; 2964 case 'u': 2965 show_utf8_chars(); 2966 break; 2967 default: 2968 if (c < 256 && isdigit(c)) 2969 digit = (c - '0'); 2970 else if (c == '+') 2971 ++digit; 2972 else if (c == '-' && digit > 0) 2973 --digit; 2974 else if (c == '>') 2975 ++repeat; 2976 else if (c == '<' && repeat > 0) 2977 --repeat; 2978 else if (c == '_') 2979 space = (space == ' ') ? '_' : ' '; 2980 else { 2981 beep(); 2982 break; 2983 } 2984 show_upper_widechars(digit * 32 + 128, repeat, space); 2985 break; 2986 } 2987 mvprintw(LINES - 2, 0, 2988 "Select: a WACS, b box, u UTF-8, 0-9,+/- non-ASCII, </> repeat, q=quit"); 2989 refresh(); 2990 } while ((c = Getchar()) != 'x' && c != 'q'); 2991 2992 Pause(); 2993 erase(); 2994 endwin(); 2995} 2996 2997#endif 2998 2999/* 3000 * Graphic-rendition test (adapted from vttest) 3001 */ 3002static void 3003test_sgr_attributes(void) 3004{ 3005 int pass; 3006 3007 for (pass = 0; pass < 2; pass++) { 3008 chtype normal = ((pass == 0 ? A_NORMAL : A_REVERSE)) | BLANK; 3009 3010 /* Use non-default colors if possible to exercise bce a little */ 3011 if (has_colors()) { 3012 init_pair(1, COLOR_WHITE, COLOR_BLUE); 3013 normal |= COLOR_PAIR(1); 3014 } 3015 bkgdset(normal); 3016 erase(); 3017 mvprintw(1, 20, "Graphic rendition test pattern:"); 3018 3019 mvprintw(4, 1, "vanilla"); 3020 3021#define set_sgr(mask) bkgdset((normal^(mask))); 3022 set_sgr(A_BOLD); 3023 mvprintw(4, 40, "bold"); 3024 3025 set_sgr(A_UNDERLINE); 3026 mvprintw(6, 6, "underline"); 3027 3028 set_sgr(A_BOLD | A_UNDERLINE); 3029 mvprintw(6, 45, "bold underline"); 3030 3031 set_sgr(A_BLINK); 3032 mvprintw(8, 1, "blink"); 3033 3034 set_sgr(A_BLINK | A_BOLD); 3035 mvprintw(8, 40, "bold blink"); 3036 3037 set_sgr(A_UNDERLINE | A_BLINK); 3038 mvprintw(10, 6, "underline blink"); 3039 3040 set_sgr(A_BOLD | A_UNDERLINE | A_BLINK); 3041 mvprintw(10, 45, "bold underline blink"); 3042 3043 set_sgr(A_REVERSE); 3044 mvprintw(12, 1, "negative"); 3045 3046 set_sgr(A_BOLD | A_REVERSE); 3047 mvprintw(12, 40, "bold negative"); 3048 3049 set_sgr(A_UNDERLINE | A_REVERSE); 3050 mvprintw(14, 6, "underline negative"); 3051 3052 set_sgr(A_BOLD | A_UNDERLINE | A_REVERSE); 3053 mvprintw(14, 45, "bold underline negative"); 3054 3055 set_sgr(A_BLINK | A_REVERSE); 3056 mvprintw(16, 1, "blink negative"); 3057 3058 set_sgr(A_BOLD | A_BLINK | A_REVERSE); 3059 mvprintw(16, 40, "bold blink negative"); 3060 3061 set_sgr(A_UNDERLINE | A_BLINK | A_REVERSE); 3062 mvprintw(18, 6, "underline blink negative"); 3063 3064 set_sgr(A_BOLD | A_UNDERLINE | A_BLINK | A_REVERSE); 3065 mvprintw(18, 45, "bold underline blink negative"); 3066 3067 bkgdset(normal); 3068 mvprintw(LINES - 2, 1, "%s background. ", pass == 0 ? "Dark" : 3069 "Light"); 3070 clrtoeol(); 3071 Pause(); 3072 } 3073 3074 bkgdset(A_NORMAL | BLANK); 3075 erase(); 3076 endwin(); 3077} 3078 3079/**************************************************************************** 3080 * 3081 * Windows and scrolling tester. 3082 * 3083 ****************************************************************************/ 3084 3085#define BOTLINES 4 /* number of line stolen from screen bottom */ 3086 3087typedef struct { 3088 int y, x; 3089} pair; 3090 3091#define FRAME struct frame 3092FRAME 3093{ 3094 FRAME *next, *last; 3095 bool do_scroll; 3096 bool do_keypad; 3097 WINDOW *wind; 3098}; 3099 3100#ifdef NCURSES_VERSION 3101#define keypad_active(win) (win)->_use_keypad 3102#define scroll_active(win) (win)->_scroll 3103#else 3104#define keypad_active(win) FALSE 3105#define scroll_active(win) FALSE 3106#endif 3107 3108/* We need to know if these flags are actually set, so don't look in FRAME. 3109 * These names are known to work with SVr4 curses as well as ncurses. The 3110 * _use_keypad name does not work with Solaris 8. 3111 */ 3112static bool 3113HaveKeypad(FRAME * curp) 3114{ 3115 WINDOW *win = (curp ? curp->wind : stdscr); 3116 return keypad_active(win); 3117} 3118 3119static bool 3120HaveScroll(FRAME * curp) 3121{ 3122 WINDOW *win = (curp ? curp->wind : stdscr); 3123 return scroll_active(win); 3124} 3125 3126static void 3127newwin_legend(FRAME * curp) 3128{ 3129 static const struct { 3130 const char *msg; 3131 int code; 3132 } legend[] = { 3133 { 3134 "^C = create window", 0 3135 }, 3136 { 3137 "^N = next window", 0 3138 }, 3139 { 3140 "^P = previous window", 0 3141 }, 3142 { 3143 "^F = scroll forward", 0 3144 }, 3145 { 3146 "^B = scroll backward", 0 3147 }, 3148 { 3149 "^K = keypad(%s)", 1 3150 }, 3151 { 3152 "^S = scrollok(%s)", 2 3153 }, 3154 { 3155 "^W = save window to file", 0 3156 }, 3157 { 3158 "^R = restore window", 0 3159 }, 3160#if HAVE_WRESIZE 3161 { 3162 "^X = resize", 0 3163 }, 3164#endif 3165 { 3166 "^Q%s = exit", 3 3167 } 3168 }; 3169 size_t n; 3170 int x; 3171 bool do_keypad = HaveKeypad(curp); 3172 bool do_scroll = HaveScroll(curp); 3173 char buf[BUFSIZ]; 3174 3175 move(LINES - 4, 0); 3176 for (n = 0; n < SIZEOF(legend); n++) { 3177 switch (legend[n].code) { 3178 default: 3179 strcpy(buf, legend[n].msg); 3180 break; 3181 case 1: 3182 sprintf(buf, legend[n].msg, do_keypad ? "yes" : "no"); 3183 break; 3184 case 2: 3185 sprintf(buf, legend[n].msg, do_scroll ? "yes" : "no"); 3186 break; 3187 case 3: 3188 sprintf(buf, legend[n].msg, do_keypad ? "/ESC" : ""); 3189 break; 3190 } 3191 x = getcurx(stdscr); 3192 addstr((COLS < (x + 3 + (int) strlen(buf))) ? "\n" : (n ? ", " : "")); 3193 addstr(buf); 3194 } 3195 clrtoeol(); 3196} 3197 3198static void 3199transient(FRAME * curp, NCURSES_CONST char *msg) 3200{ 3201 newwin_legend(curp); 3202 if (msg) { 3203 mvaddstr(LINES - 1, 0, msg); 3204 refresh(); 3205 napms(1000); 3206 } 3207 3208 move(LINES - 1, 0); 3209 printw("%s characters are echoed, window should %sscroll.", 3210 HaveKeypad(curp) ? "Non-arrow" : "All other", 3211 HaveScroll(curp) ? "" : "not "); 3212 clrtoeol(); 3213} 3214 3215static void 3216newwin_report(FRAME * curp) 3217/* report on the cursor's current position, then restore it */ 3218{ 3219 WINDOW *win = (curp != 0) ? curp->wind : stdscr; 3220 int y, x; 3221 3222 if (win != stdscr) 3223 transient(curp, (char *) 0); 3224 getyx(win, y, x); 3225 move(LINES - 1, COLS - 17); 3226 printw("Y = %2d X = %2d", y, x); 3227 if (win != stdscr) 3228 refresh(); 3229 else 3230 wmove(win, y, x); 3231} 3232 3233static pair * 3234selectcell(int uli, int ulj, int lri, int lrj) 3235/* arrows keys move cursor, return location at current on non-arrow key */ 3236{ 3237 static pair res; /* result cell */ 3238 int si = lri - uli + 1; /* depth of the select area */ 3239 int sj = lrj - ulj + 1; /* width of the select area */ 3240 int i = 0, j = 0; /* offsets into the select area */ 3241 3242 res.y = uli; 3243 res.x = ulj; 3244 for (;;) { 3245 move(uli + i, ulj + j); 3246 newwin_report((FRAME *) 0); 3247 3248 switch (Getchar()) { 3249 case KEY_UP: 3250 i += si - 1; 3251 break; 3252 case KEY_DOWN: 3253 i++; 3254 break; 3255 case KEY_LEFT: 3256 j += sj - 1; 3257 break; 3258 case KEY_RIGHT: 3259 j++; 3260 break; 3261 case QUIT: 3262 case ESCAPE: 3263 return ((pair *) 0); 3264#ifdef NCURSES_MOUSE_VERSION 3265 case KEY_MOUSE: 3266 { 3267 MEVENT event; 3268 3269 getmouse(&event); 3270 if (event.y > uli && event.x > ulj) { 3271 i = event.y - uli; 3272 j = event.x - ulj; 3273 } else { 3274 beep(); 3275 break; 3276 } 3277 } 3278 /* FALLTHRU */ 3279#endif 3280 default: 3281 res.y = uli + i; 3282 res.x = ulj + j; 3283 return (&res); 3284 } 3285 i %= si; 3286 j %= sj; 3287 } 3288} 3289 3290static void 3291outerbox(pair ul, pair lr, bool onoff) 3292/* draw or erase a box *outside* the given pair of corners */ 3293{ 3294 mvaddch(ul.y - 1, lr.x - 1, onoff ? ACS_ULCORNER : ' '); 3295 mvaddch(ul.y - 1, lr.x + 1, onoff ? ACS_URCORNER : ' '); 3296 mvaddch(lr.y + 1, lr.x + 1, onoff ? ACS_LRCORNER : ' '); 3297 mvaddch(lr.y + 1, ul.x - 1, onoff ? ACS_LLCORNER : ' '); 3298 move(ul.y - 1, ul.x); 3299 hline(onoff ? ACS_HLINE : ' ', lr.x - ul.x + 1); 3300 move(ul.y, ul.x - 1); 3301 vline(onoff ? ACS_VLINE : ' ', lr.y - ul.y + 1); 3302 move(lr.y + 1, ul.x); 3303 hline(onoff ? ACS_HLINE : ' ', lr.x - ul.x + 1); 3304 move(ul.y, lr.x + 1); 3305 vline(onoff ? ACS_VLINE : ' ', lr.y - ul.y + 1); 3306} 3307 3308static WINDOW * 3309getwindow(void) 3310/* Ask user for a window definition */ 3311{ 3312 WINDOW *rwindow; 3313 pair ul, lr, *tmp; 3314 3315 move(0, 0); 3316 clrtoeol(); 3317 addstr("Use arrows to move cursor, anything else to mark corner 1"); 3318 refresh(); 3319 if ((tmp = selectcell(2, 1, LINES - BOTLINES - 2, COLS - 2)) == (pair *) 0) 3320 return ((WINDOW *) 0); 3321 memcpy(&ul, tmp, sizeof(pair)); 3322 mvaddch(ul.y - 1, ul.x - 1, ACS_ULCORNER); 3323 move(0, 0); 3324 clrtoeol(); 3325 addstr("Use arrows to move cursor, anything else to mark corner 2"); 3326 refresh(); 3327 if ((tmp = selectcell(ul.y, ul.x, LINES - BOTLINES - 2, COLS - 2)) == 3328 (pair *) 0) 3329 return ((WINDOW *) 0); 3330 memcpy(&lr, tmp, sizeof(pair)); 3331 3332 rwindow = subwin(stdscr, lr.y - ul.y + 1, lr.x - ul.x + 1, ul.y, ul.x); 3333 3334 outerbox(ul, lr, TRUE); 3335 refresh(); 3336 3337 wrefresh(rwindow); 3338 3339 move(0, 0); 3340 clrtoeol(); 3341 return (rwindow); 3342} 3343 3344static void 3345newwin_move(FRAME * curp, int dy, int dx) 3346{ 3347 WINDOW *win = (curp != 0) ? curp->wind : stdscr; 3348 int cur_y, cur_x; 3349 int max_y, max_x; 3350 3351 getyx(win, cur_y, cur_x); 3352 getmaxyx(win, max_y, max_x); 3353 if ((cur_x += dx) < 0) 3354 cur_x = 0; 3355 else if (cur_x >= max_x) 3356 cur_x = max_x - 1; 3357 if ((cur_y += dy) < 0) 3358 cur_y = 0; 3359 else if (cur_y >= max_y) 3360 cur_y = max_y - 1; 3361 wmove(win, cur_y, cur_x); 3362} 3363 3364static FRAME * 3365delete_framed(FRAME * fp, bool showit) 3366{ 3367 FRAME *np; 3368 3369 fp->last->next = fp->next; 3370 fp->next->last = fp->last; 3371 3372 if (showit) { 3373 werase(fp->wind); 3374 wrefresh(fp->wind); 3375 } 3376 delwin(fp->wind); 3377 3378 np = (fp == fp->next) ? 0 : fp->next; 3379 free(fp); 3380 return np; 3381} 3382 3383static void 3384acs_and_scroll(void) 3385/* Demonstrate windows */ 3386{ 3387 int c, i; 3388 FILE *fp; 3389 FRAME *current = (FRAME *) 0, *neww; 3390 WINDOW *usescr = stdscr; 3391 3392#define DUMPFILE "screendump" 3393 3394#ifdef NCURSES_MOUSE_VERSION 3395 mousemask(BUTTON1_CLICKED, (mmask_t *) 0); 3396#endif 3397 c = CTRL('C'); 3398 raw(); 3399 do { 3400 transient((FRAME *) 0, (char *) 0); 3401 switch (c) { 3402 case CTRL('C'): 3403 neww = (FRAME *) calloc(1, sizeof(FRAME)); 3404 if ((neww->wind = getwindow()) == (WINDOW *) 0) 3405 goto breakout; 3406 3407 if (current == 0) { /* First element, */ 3408 neww->next = neww; /* so point it at itself */ 3409 neww->last = neww; 3410 } else { 3411 neww->next = current->next; 3412 neww->last = current; 3413 neww->last->next = neww; 3414 neww->next->last = neww; 3415 } 3416 current = neww; 3417 /* SVr4 curses sets the keypad on all newly-created windows to 3418 * false. Someone reported that PDCurses makes new windows inherit 3419 * this flag. Remove the following 'keypad()' call to test this 3420 */ 3421 keypad(current->wind, TRUE); 3422 current->do_keypad = HaveKeypad(current); 3423 current->do_scroll = HaveScroll(current); 3424 break; 3425 3426 case CTRL('N'): /* go to next window */ 3427 if (current) 3428 current = current->next; 3429 break; 3430 3431 case CTRL('P'): /* go to previous window */ 3432 if (current) 3433 current = current->last; 3434 break; 3435 3436 case CTRL('F'): /* scroll current window forward */ 3437 if (current) 3438 wscrl(current->wind, 1); 3439 break; 3440 3441 case CTRL('B'): /* scroll current window backwards */ 3442 if (current) 3443 wscrl(current->wind, -1); 3444 break; 3445 3446 case CTRL('K'): /* toggle keypad mode for current */ 3447 if (current) { 3448 current->do_keypad = !current->do_keypad; 3449 keypad(current->wind, current->do_keypad); 3450 } 3451 break; 3452 3453 case CTRL('S'): 3454 if (current) { 3455 current->do_scroll = !current->do_scroll; 3456 scrollok(current->wind, current->do_scroll); 3457 } 3458 break; 3459 3460 case CTRL('W'): /* save and delete window */ 3461 if (current == current->next) { 3462 transient(current, "Will not save/delete ONLY window"); 3463 break; 3464 } else if ((fp = fopen(DUMPFILE, "w")) == (FILE *) 0) { 3465 transient(current, "Can't open screen dump file"); 3466 } else { 3467 (void) putwin(current->wind, fp); 3468 (void) fclose(fp); 3469 3470 current = delete_framed(current, TRUE); 3471 } 3472 break; 3473 3474 case CTRL('R'): /* restore window */ 3475 if ((fp = fopen(DUMPFILE, "r")) == (FILE *) 0) { 3476 transient(current, "Can't open screen dump file"); 3477 } else { 3478 neww = (FRAME *) calloc(1, sizeof(FRAME)); 3479 3480 neww->next = current->next; 3481 neww->last = current; 3482 neww->last->next = neww; 3483 neww->next->last = neww; 3484 3485 neww->wind = getwin(fp); 3486 (void) fclose(fp); 3487 3488 wrefresh(neww->wind); 3489 } 3490 break; 3491 3492#if HAVE_WRESIZE 3493 case CTRL('X'): /* resize window */ 3494 if (current) { 3495 pair *tmp, ul, lr; 3496 int mx, my; 3497 3498 move(0, 0); 3499 clrtoeol(); 3500 addstr("Use arrows to move cursor, anything else to mark new corner"); 3501 refresh(); 3502 3503 getbegyx(current->wind, ul.y, ul.x); 3504 3505 tmp = selectcell(ul.y, ul.x, LINES - BOTLINES - 2, COLS - 2); 3506 if (tmp == (pair *) 0) { 3507 beep(); 3508 break; 3509 } 3510 3511 getmaxyx(current->wind, lr.y, lr.x); 3512 lr.y += (ul.y - 1); 3513 lr.x += (ul.x - 1); 3514 outerbox(ul, lr, FALSE); 3515 wnoutrefresh(stdscr); 3516 3517 /* strictly cosmetic hack for the test */ 3518 getmaxyx(current->wind, my, mx); 3519 if (my > tmp->y - ul.y) { 3520 getyx(current->wind, lr.y, lr.x); 3521 wmove(current->wind, tmp->y - ul.y + 1, 0); 3522 wclrtobot(current->wind); 3523 wmove(current->wind, lr.y, lr.x); 3524 } 3525 if (mx > tmp->x - ul.x) 3526 for (i = 0; i < my; i++) { 3527 wmove(current->wind, i, tmp->x - ul.x + 1); 3528 wclrtoeol(current->wind); 3529 } 3530 wnoutrefresh(current->wind); 3531 3532 memcpy(&lr, tmp, sizeof(pair)); 3533 (void) wresize(current->wind, lr.y - ul.y + 0, lr.x - ul.x + 0); 3534 3535 getbegyx(current->wind, ul.y, ul.x); 3536 getmaxyx(current->wind, lr.y, lr.x); 3537 lr.y += (ul.y - 1); 3538 lr.x += (ul.x - 1); 3539 outerbox(ul, lr, TRUE); 3540 wnoutrefresh(stdscr); 3541 3542 wnoutrefresh(current->wind); 3543 move(0, 0); 3544 clrtoeol(); 3545 doupdate(); 3546 } 3547 break; 3548#endif /* HAVE_WRESIZE */ 3549 3550 case KEY_F(10): /* undocumented --- use this to test area clears */ 3551 selectcell(0, 0, LINES - 1, COLS - 1); 3552 clrtobot(); 3553 refresh(); 3554 break; 3555 3556 case KEY_UP: 3557 newwin_move(current, -1, 0); 3558 break; 3559 case KEY_DOWN: 3560 newwin_move(current, 1, 0); 3561 break; 3562 case KEY_LEFT: 3563 newwin_move(current, 0, -1); 3564 break; 3565 case KEY_RIGHT: 3566 newwin_move(current, 0, 1); 3567 break; 3568 3569 case KEY_BACKSPACE: 3570 /* FALLTHROUGH */ 3571 case KEY_DC: 3572 { 3573 int y, x; 3574 getyx(current->wind, y, x); 3575 if (--x < 0) { 3576 if (--y < 0) 3577 break; 3578 x = getmaxx(current->wind) - 1; 3579 } 3580 mvwdelch(current->wind, y, x); 3581 } 3582 break; 3583 3584 case '\r': 3585 c = '\n'; 3586 /* FALLTHROUGH */ 3587 3588 default: 3589 if (current) 3590 waddch(current->wind, (chtype) c); 3591 else 3592 beep(); 3593 break; 3594 } 3595 newwin_report(current); 3596 usescr = (current ? current->wind : stdscr); 3597 wrefresh(usescr); 3598 } while 3599 ((c = wGetchar(usescr)) != QUIT 3600 && !((c == ESCAPE) && (keypad_active(usescr))) 3601 && (c != ERR)); 3602 3603 breakout: 3604 while (current != 0) 3605 current = delete_framed(current, FALSE); 3606 3607 scrollok(stdscr, TRUE); /* reset to driver's default */ 3608#ifdef NCURSES_MOUSE_VERSION 3609 mousemask(0, (mmask_t *) 0); 3610#endif 3611 noraw(); 3612 erase(); 3613 endwin(); 3614} 3615 3616/**************************************************************************** 3617 * 3618 * Panels tester 3619 * 3620 ****************************************************************************/ 3621 3622#if USE_LIBPANEL 3623static int nap_msec = 1; 3624 3625static NCURSES_CONST char *mod[] = 3626{ 3627 "test ", 3628 "TEST ", 3629 "(**) ", 3630 "*()* ", 3631 "<--> ", 3632 "LAST " 3633}; 3634 3635/*+------------------------------------------------------------------------- 3636 wait_a_while(msec) 3637--------------------------------------------------------------------------*/ 3638static void 3639wait_a_while(int msec GCC_UNUSED) 3640{ 3641#if HAVE_NAPMS 3642 if (nap_msec == 1) 3643 wGetchar(stdscr); 3644 else 3645 napms(nap_msec); 3646#else 3647 if (nap_msec == 1) 3648 wGetchar(stdscr); 3649 else if (msec > 1000) 3650 sleep((unsigned) msec / 1000); 3651 else 3652 sleep(1); 3653#endif 3654} /* end of wait_a_while */ 3655 3656/*+------------------------------------------------------------------------- 3657 saywhat(text) 3658--------------------------------------------------------------------------*/ 3659static void 3660saywhat(NCURSES_CONST char *text) 3661{ 3662 wmove(stdscr, LINES - 1, 0); 3663 wclrtoeol(stdscr); 3664 waddstr(stdscr, text); 3665} /* end of saywhat */ 3666 3667/*+------------------------------------------------------------------------- 3668 mkpanel(rows,cols,tly,tlx) - alloc a win and panel and associate them 3669--------------------------------------------------------------------------*/ 3670static PANEL * 3671mkpanel(unsigned color, int rows, int cols, int tly, int tlx) 3672{ 3673 WINDOW *win; 3674 PANEL *pan = 0; 3675 3676 if ((win = newwin(rows, cols, tly, tlx)) != 0) { 3677 if ((pan = new_panel(win)) == 0) { 3678 delwin(win); 3679 } else if (has_colors()) { 3680 int fg = (color == COLOR_BLUE) ? COLOR_WHITE : COLOR_BLACK; 3681 int bg = color; 3682 init_pair(color, fg, bg); 3683 wbkgdset(win, COLOR_PAIR(color) | ' '); 3684 } else { 3685 wbkgdset(win, A_BOLD | ' '); 3686 } 3687 } 3688 return pan; 3689} /* end of mkpanel */ 3690 3691/*+------------------------------------------------------------------------- 3692 rmpanel(pan) 3693--------------------------------------------------------------------------*/ 3694static void 3695rmpanel(PANEL * pan) 3696{ 3697 WINDOW *win = panel_window(pan); 3698 del_panel(pan); 3699 delwin(win); 3700} /* end of rmpanel */ 3701 3702/*+------------------------------------------------------------------------- 3703 pflush() 3704--------------------------------------------------------------------------*/ 3705static void 3706pflush(void) 3707{ 3708 update_panels(); 3709 doupdate(); 3710} /* end of pflush */ 3711 3712/*+------------------------------------------------------------------------- 3713 fill_panel(win) 3714--------------------------------------------------------------------------*/ 3715static void 3716fill_panel(PANEL * pan) 3717{ 3718 WINDOW *win = panel_window(pan); 3719 int num = ((const char *) panel_userptr(pan))[1]; 3720 int y, x; 3721 3722 wmove(win, 1, 1); 3723 wprintw(win, "-pan%c-", num); 3724 wclrtoeol(win); 3725 box(win, 0, 0); 3726 for (y = 2; y < getmaxy(win) - 1; y++) { 3727 for (x = 1; x < getmaxx(win) - 1; x++) { 3728 wmove(win, y, x); 3729 waddch(win, UChar(num)); 3730 } 3731 } 3732} /* end of fill_panel */ 3733 3734static void 3735demo_panels(void) 3736{ 3737 int itmp; 3738 register int y, x; 3739 3740 refresh(); 3741 3742 for (y = 0; y < LINES - 1; y++) { 3743 for (x = 0; x < COLS; x++) 3744 wprintw(stdscr, "%d", (y + x) % 10); 3745 } 3746 for (y = 0; y < 5; y++) { 3747 PANEL *p1; 3748 PANEL *p2; 3749 PANEL *p3; 3750 PANEL *p4; 3751 PANEL *p5; 3752 3753 p1 = mkpanel(COLOR_RED, 3754 LINES / 2 - 2, 3755 COLS / 8 + 1, 3756 0, 3757 0); 3758 set_panel_userptr(p1, (NCURSES_CONST void *) "p1"); 3759 3760 p2 = mkpanel(COLOR_GREEN, 3761 LINES / 2 + 1, 3762 COLS / 7, 3763 LINES / 4, 3764 COLS / 10); 3765 set_panel_userptr(p2, (NCURSES_CONST void *) "p2"); 3766 3767 p3 = mkpanel(COLOR_YELLOW, 3768 LINES / 4, 3769 COLS / 10, 3770 LINES / 2, 3771 COLS / 9); 3772 set_panel_userptr(p3, (NCURSES_CONST void *) "p3"); 3773 3774 p4 = mkpanel(COLOR_BLUE, 3775 LINES / 2 - 2, 3776 COLS / 8, 3777 LINES / 2 - 2, 3778 COLS / 3); 3779 set_panel_userptr(p4, (NCURSES_CONST void *) "p4"); 3780 3781 p5 = mkpanel(COLOR_MAGENTA, 3782 LINES / 2 - 2, 3783 COLS / 8, 3784 LINES / 2, 3785 COLS / 2 - 2); 3786 set_panel_userptr(p5, (NCURSES_CONST void *) "p5"); 3787 3788 fill_panel(p1); 3789 fill_panel(p2); 3790 fill_panel(p3); 3791 fill_panel(p4); 3792 fill_panel(p5); 3793 hide_panel(p4); 3794 hide_panel(p5); 3795 pflush(); 3796 saywhat("press any key to continue"); 3797 wait_a_while(nap_msec); 3798 3799 saywhat("h3 s1 s2 s4 s5; press any key to continue"); 3800 move_panel(p1, 0, 0); 3801 hide_panel(p3); 3802 show_panel(p1); 3803 show_panel(p2); 3804 show_panel(p4); 3805 show_panel(p5); 3806 pflush(); 3807 wait_a_while(nap_msec); 3808 3809 saywhat("s1; press any key to continue"); 3810 show_panel(p1); 3811 pflush(); 3812 wait_a_while(nap_msec); 3813 3814 saywhat("s2; press any key to continue"); 3815 show_panel(p2); 3816 pflush(); 3817 wait_a_while(nap_msec); 3818 3819 saywhat("m2; press any key to continue"); 3820 move_panel(p2, LINES / 3 + 1, COLS / 8); 3821 pflush(); 3822 wait_a_while(nap_msec); 3823 3824 saywhat("s3;"); 3825 show_panel(p3); 3826 pflush(); 3827 wait_a_while(nap_msec); 3828 3829 saywhat("m3; press any key to continue"); 3830 move_panel(p3, LINES / 4 + 1, COLS / 15); 3831 pflush(); 3832 wait_a_while(nap_msec); 3833 3834 saywhat("b3; press any key to continue"); 3835 bottom_panel(p3); 3836 pflush(); 3837 wait_a_while(nap_msec); 3838 3839 saywhat("s4; press any key to continue"); 3840 show_panel(p4); 3841 pflush(); 3842 wait_a_while(nap_msec); 3843 3844 saywhat("s5; press any key to continue"); 3845 show_panel(p5); 3846 pflush(); 3847 wait_a_while(nap_msec); 3848 3849 saywhat("t3; press any key to continue"); 3850 top_panel(p3); 3851 pflush(); 3852 wait_a_while(nap_msec); 3853 3854 saywhat("t1; press any key to continue"); 3855 top_panel(p1); 3856 pflush(); 3857 wait_a_while(nap_msec); 3858 3859 saywhat("t2; press any key to continue"); 3860 top_panel(p2); 3861 pflush(); 3862 wait_a_while(nap_msec); 3863 3864 saywhat("t3; press any key to continue"); 3865 top_panel(p3); 3866 pflush(); 3867 wait_a_while(nap_msec); 3868 3869 saywhat("t4; press any key to continue"); 3870 top_panel(p4); 3871 pflush(); 3872 wait_a_while(nap_msec); 3873 3874 for (itmp = 0; itmp < 6; itmp++) { 3875 WINDOW *w4 = panel_window(p4); 3876 WINDOW *w5 = panel_window(p5); 3877 3878 saywhat("m4; press any key to continue"); 3879 wmove(w4, LINES / 8, 1); 3880 waddstr(w4, mod[itmp]); 3881 move_panel(p4, LINES / 6, itmp * (COLS / 8)); 3882 wmove(w5, LINES / 6, 1); 3883 waddstr(w5, mod[itmp]); 3884 pflush(); 3885 wait_a_while(nap_msec); 3886 3887 saywhat("m5; press any key to continue"); 3888 wmove(w4, LINES / 6, 1); 3889 waddstr(w4, mod[itmp]); 3890 move_panel(p5, LINES / 3 - 1, (itmp * 10) + 6); 3891 wmove(w5, LINES / 8, 1); 3892 waddstr(w5, mod[itmp]); 3893 pflush(); 3894 wait_a_while(nap_msec); 3895 } 3896 3897 saywhat("m4; press any key to continue"); 3898 move_panel(p4, LINES / 6, itmp * (COLS / 8)); 3899 pflush(); 3900 wait_a_while(nap_msec); 3901 3902 saywhat("t5; press any key to continue"); 3903 top_panel(p5); 3904 pflush(); 3905 wait_a_while(nap_msec); 3906 3907 saywhat("t2; press any key to continue"); 3908 top_panel(p2); 3909 pflush(); 3910 wait_a_while(nap_msec); 3911 3912 saywhat("t1; press any key to continue"); 3913 top_panel(p1); 3914 pflush(); 3915 wait_a_while(nap_msec); 3916 3917 saywhat("d2; press any key to continue"); 3918 rmpanel(p2); 3919 pflush(); 3920 wait_a_while(nap_msec); 3921 3922 saywhat("h3; press any key to continue"); 3923 hide_panel(p3); 3924 pflush(); 3925 wait_a_while(nap_msec); 3926 3927 saywhat("d1; press any key to continue"); 3928 rmpanel(p1); 3929 pflush(); 3930 wait_a_while(nap_msec); 3931 3932 saywhat("d4; press any key to continue"); 3933 rmpanel(p4); 3934 pflush(); 3935 wait_a_while(nap_msec); 3936 3937 saywhat("d5; press any key to continue"); 3938 rmpanel(p5); 3939 pflush(); 3940 3941 rmpanel(p3); 3942 pflush(); 3943 3944 wait_a_while(nap_msec); 3945 if (nap_msec == 1) 3946 break; 3947 nap_msec = 100L; 3948 } 3949 3950 erase(); 3951 endwin(); 3952} 3953 3954/**************************************************************************** 3955 * 3956 * Pad tester 3957 * 3958 ****************************************************************************/ 3959 3960#define GRIDSIZE 3 3961 3962static bool pending_pan = FALSE; 3963static bool show_panner_legend = TRUE; 3964 3965static int 3966panner_legend(int line) 3967{ 3968 static const char *const legend[] = 3969 { 3970 "Use arrow keys (or U,D,L,R) to pan, q to quit, ! to shell-out.", 3971 "Use +,- (or j,k) to grow/shrink the panner vertically.", 3972 "Use <,> (or h,l) to grow/shrink the panner horizontally.", 3973 "Number repeats. Toggle legend:? filler:a timer:t scrollmark:s." 3974 }; 3975 int n = (SIZEOF(legend) - (LINES - line)); 3976 if (line < LINES && (n >= 0)) { 3977 move(line, 0); 3978 if (show_panner_legend) 3979 printw("%s", legend[n]); 3980 clrtoeol(); 3981 return show_panner_legend; 3982 } 3983 return FALSE; 3984} 3985 3986static void 3987panner_h_cleanup(int from_y, int from_x, int to_x) 3988{ 3989 if (!panner_legend(from_y)) 3990 do_h_line(from_y, from_x, ' ', to_x); 3991} 3992 3993static void 3994panner_v_cleanup(int from_y, int from_x, int to_y) 3995{ 3996 if (!panner_legend(from_y)) 3997 do_v_line(from_y, from_x, ' ', to_y); 3998} 3999 4000static void 4001fill_pad(WINDOW *panpad, bool pan_lines) 4002{ 4003 int y, x; 4004 unsigned gridcount = 0; 4005 4006 wmove(panpad, 0, 0); 4007 for (y = 0; y < getmaxy(panpad); y++) { 4008 for (x = 0; x < getmaxx(panpad); x++) { 4009 if (y % GRIDSIZE == 0 && x % GRIDSIZE == 0) { 4010 if (y == 0 && x == 0) 4011 waddch(panpad, pan_lines ? ACS_ULCORNER : '+'); 4012 else if (y == 0) 4013 waddch(panpad, pan_lines ? ACS_TTEE : '+'); 4014 else if (y == 0 || x == 0) 4015 waddch(panpad, pan_lines ? ACS_LTEE : '+'); 4016 else 4017 waddch(panpad, (chtype) ((pan_lines ? 'a' : 'A') + 4018 (gridcount++ % 26))); 4019 } else if (y % GRIDSIZE == 0) 4020 waddch(panpad, pan_lines ? ACS_HLINE : '-'); 4021 else if (x % GRIDSIZE == 0) 4022 waddch(panpad, pan_lines ? ACS_VLINE : '|'); 4023 else 4024 waddch(panpad, ' '); 4025 } 4026 } 4027} 4028 4029static void 4030panner(WINDOW *pad, 4031 int top_x, int top_y, int porty, int portx, 4032 int (*pgetc) (WINDOW *)) 4033{ 4034#if HAVE_GETTIMEOFDAY 4035 struct timeval before, after; 4036 bool timing = TRUE; 4037#endif 4038 bool pan_lines = FALSE; 4039 bool scrollers = TRUE; 4040 int basex = 0; 4041 int basey = 0; 4042 int pxmax, pymax, lowend, highend, c; 4043 4044 getmaxyx(pad, pymax, pxmax); 4045 scrollok(stdscr, FALSE); /* we don't want stdscr to scroll! */ 4046 4047 c = KEY_REFRESH; 4048 do { 4049#ifdef NCURSES_VERSION 4050 /* 4051 * During shell-out, the user may have resized the window. Adjust 4052 * the port size of the pad to accommodate this. Ncurses automatically 4053 * resizes all of the normal windows to fit on the new screen. 4054 */ 4055 if (top_x > COLS) 4056 top_x = COLS; 4057 if (portx > COLS) 4058 portx = COLS; 4059 if (top_y > LINES) 4060 top_y = LINES; 4061 if (porty > LINES) 4062 porty = LINES; 4063#endif 4064 switch (c) { 4065 case KEY_REFRESH: 4066 erase(); 4067 4068 /* FALLTHRU */ 4069 case '?': 4070 if (c == '?') 4071 show_panner_legend = !show_panner_legend; 4072 panner_legend(LINES - 4); 4073 panner_legend(LINES - 3); 4074 panner_legend(LINES - 2); 4075 panner_legend(LINES - 1); 4076 break; 4077 case 'a': 4078 pan_lines = !pan_lines; 4079 fill_pad(pad, pan_lines); 4080 pending_pan = FALSE; 4081 break; 4082 4083#if HAVE_GETTIMEOFDAY 4084 case 't': 4085 timing = !timing; 4086 if (!timing) 4087 panner_legend(LINES - 1); 4088 break; 4089#endif 4090 case 's': 4091 scrollers = !scrollers; 4092 break; 4093 4094 /* Move the top-left corner of the pad, keeping the bottom-right 4095 * corner fixed. 4096 */ 4097 case 'h': /* increase-columns: move left edge to left */ 4098 if (top_x <= 0) 4099 beep(); 4100 else { 4101 panner_v_cleanup(top_y, top_x, porty); 4102 top_x--; 4103 } 4104 break; 4105 4106 case 'j': /* decrease-lines: move top-edge down */ 4107 if (top_y >= porty) 4108 beep(); 4109 else { 4110 panner_h_cleanup(top_y - 1, top_x - (top_x > 0), portx); 4111 top_y++; 4112 } 4113 break; 4114 4115 case 'k': /* increase-lines: move top-edge up */ 4116 if (top_y <= 0) 4117 beep(); 4118 else { 4119 top_y--; 4120 panner_h_cleanup(top_y, top_x, portx); 4121 } 4122 break; 4123 4124 case 'l': /* decrease-columns: move left-edge to right */ 4125 if (top_x >= portx) 4126 beep(); 4127 else { 4128 panner_v_cleanup(top_y - (top_y > 0), top_x - 1, porty); 4129 top_x++; 4130 } 4131 break; 4132 4133 /* Move the bottom-right corner of the pad, keeping the top-left 4134 * corner fixed. 4135 */ 4136 case KEY_IC: /* increase-columns: move right-edge to right */ 4137 if (portx >= pxmax || portx >= COLS) 4138 beep(); 4139 else { 4140 panner_v_cleanup(top_y - (top_y > 0), portx - 1, porty); 4141 ++portx; 4142 } 4143 break; 4144 4145 case KEY_IL: /* increase-lines: move bottom-edge down */ 4146 if (porty >= pymax || porty >= LINES) 4147 beep(); 4148 else { 4149 panner_h_cleanup(porty - 1, top_x - (top_x > 0), portx); 4150 ++porty; 4151 } 4152 break; 4153 4154 case KEY_DC: /* decrease-columns: move bottom edge up */ 4155 if (portx <= top_x) 4156 beep(); 4157 else { 4158 portx--; 4159 panner_v_cleanup(top_y - (top_y > 0), portx, porty); 4160 } 4161 break; 4162 4163 case KEY_DL: /* decrease-lines */ 4164 if (porty <= top_y) 4165 beep(); 4166 else { 4167 porty--; 4168 panner_h_cleanup(porty, top_x - (top_x > 0), portx); 4169 } 4170 break; 4171 4172 case KEY_LEFT: /* pan leftwards */ 4173 if (basex > 0) 4174 basex--; 4175 else 4176 beep(); 4177 break; 4178 4179 case KEY_RIGHT: /* pan rightwards */ 4180 if (basex + portx - (pymax > porty) < pxmax) 4181 basex++; 4182 else 4183 beep(); 4184 break; 4185 4186 case KEY_UP: /* pan upwards */ 4187 if (basey > 0) 4188 basey--; 4189 else 4190 beep(); 4191 break; 4192 4193 case KEY_DOWN: /* pan downwards */ 4194 if (basey + porty - (pxmax > portx) < pymax) 4195 basey++; 4196 else 4197 beep(); 4198 break; 4199 4200 case 'H': 4201 case KEY_HOME: 4202 case KEY_FIND: 4203 basey = 0; 4204 break; 4205 4206 case 'E': 4207 case KEY_END: 4208 case KEY_SELECT: 4209 basey = pymax - porty; 4210 if (basey < 0) 4211 basey = 0; 4212 break; 4213 4214 default: 4215 beep(); 4216 break; 4217 } 4218 4219 mvaddch(top_y - 1, top_x - 1, ACS_ULCORNER); 4220 do_v_line(top_y, top_x - 1, ACS_VLINE, porty); 4221 do_h_line(top_y - 1, top_x, ACS_HLINE, portx); 4222 4223 if (scrollers && (pxmax > portx - 1)) { 4224 int length = (portx - top_x - 1); 4225 float ratio = ((float) length) / ((float) pxmax); 4226 4227 lowend = (int) (top_x + (basex * ratio)); 4228 highend = (int) (top_x + ((basex + length) * ratio)); 4229 4230 do_h_line(porty - 1, top_x, ACS_HLINE, lowend); 4231 if (highend < portx) { 4232 attron(A_REVERSE); 4233 do_h_line(porty - 1, lowend, ' ', highend + 1); 4234 attroff(A_REVERSE); 4235 do_h_line(porty - 1, highend + 1, ACS_HLINE, portx); 4236 } 4237 } else 4238 do_h_line(porty - 1, top_x, ACS_HLINE, portx); 4239 4240 if (scrollers && (pymax > porty - 1)) { 4241 int length = (porty - top_y - 1); 4242 float ratio = ((float) length) / ((float) pymax); 4243 4244 lowend = (int) (top_y + (basey * ratio)); 4245 highend = (int) (top_y + ((basey + length) * ratio)); 4246 4247 do_v_line(top_y, portx - 1, ACS_VLINE, lowend); 4248 if (highend < porty) { 4249 attron(A_REVERSE); 4250 do_v_line(lowend, portx - 1, ' ', highend + 1); 4251 attroff(A_REVERSE); 4252 do_v_line(highend + 1, portx - 1, ACS_VLINE, porty); 4253 } 4254 } else 4255 do_v_line(top_y, portx - 1, ACS_VLINE, porty); 4256 4257 mvaddch(top_y - 1, portx - 1, ACS_URCORNER); 4258 mvaddch(porty - 1, top_x - 1, ACS_LLCORNER); 4259 mvaddch(porty - 1, portx - 1, ACS_LRCORNER); 4260 4261 if (!pending_pan) { 4262#if HAVE_GETTIMEOFDAY 4263 gettimeofday(&before, 0); 4264#endif 4265 wnoutrefresh(stdscr); 4266 4267 pnoutrefresh(pad, 4268 basey, basex, 4269 top_y, top_x, 4270 porty - (pxmax > portx) - 1, 4271 portx - (pymax > porty) - 1); 4272 4273 doupdate(); 4274#if HAVE_GETTIMEOFDAY 4275 if (timing) { 4276 double elapsed; 4277 gettimeofday(&after, 0); 4278 elapsed = (after.tv_sec + after.tv_usec / 1.0e6) 4279 - (before.tv_sec + before.tv_usec / 1.0e6); 4280 move(LINES - 1, COLS - 12); 4281 printw("Secs: %2.03f", elapsed); 4282 refresh(); 4283 } 4284#endif 4285 } 4286 4287 } while 4288 ((c = pgetc(pad)) != KEY_EXIT); 4289 4290 scrollok(stdscr, TRUE); /* reset to driver's default */ 4291} 4292 4293static int 4294padgetch(WINDOW *win) 4295{ 4296 static int count; 4297 static int last; 4298 int c; 4299 4300 if ((pending_pan = (count > 0)) != FALSE) { 4301 count--; 4302 pending_pan = (count != 0); 4303 } else { 4304 for (;;) { 4305 switch (c = wGetchar(win)) { 4306 case '!': 4307 ShellOut(FALSE); 4308 /* FALLTHRU */ 4309 case CTRL('r'): 4310 endwin(); 4311 refresh(); 4312 c = KEY_REFRESH; 4313 break; 4314 case CTRL('l'): 4315 c = KEY_REFRESH; 4316 break; 4317 case 'U': 4318 c = KEY_UP; 4319 break; 4320 case 'D': 4321 c = KEY_DOWN; 4322 break; 4323 case 'R': 4324 c = KEY_RIGHT; 4325 break; 4326 case 'L': 4327 c = KEY_LEFT; 4328 break; 4329 case '+': 4330 c = KEY_IL; 4331 break; 4332 case '-': 4333 c = KEY_DL; 4334 break; 4335 case '>': 4336 c = KEY_IC; 4337 break; 4338 case '<': 4339 c = KEY_DC; 4340 break; 4341 case ERR: /* FALLTHRU */ 4342 case 'q': 4343 count = 0; 4344 c = KEY_EXIT; 4345 break; 4346 default: 4347 if (c >= '0' && c <= '9') { 4348 count = count * 10 + (c - '0'); 4349 continue; 4350 } 4351 break; 4352 } 4353 last = c; 4354 break; 4355 } 4356 if (count > 0) 4357 count--; 4358 } 4359 return (last); 4360} 4361 4362#define PAD_HIGH 200 4363#define PAD_WIDE 200 4364 4365static void 4366demo_pad(void) 4367/* Demonstrate pads. */ 4368{ 4369 WINDOW *panpad = newpad(PAD_HIGH, PAD_WIDE); 4370 4371 if (panpad == 0) { 4372 Cannot("cannot create requested pad"); 4373 return; 4374 } 4375 4376 fill_pad(panpad, FALSE); 4377 4378 panner_legend(LINES - 4); 4379 panner_legend(LINES - 3); 4380 panner_legend(LINES - 2); 4381 panner_legend(LINES - 1); 4382 4383 keypad(panpad, TRUE); 4384 4385 /* Make the pad (initially) narrow enough that a trace file won't wrap. 4386 * We'll still be able to widen it during a test, since that's required 4387 * for testing boundaries. 4388 */ 4389 panner(panpad, 2, 2, LINES - 5, COLS - 15, padgetch); 4390 4391 delwin(panpad); 4392 endwin(); 4393 erase(); 4394} 4395#endif /* USE_LIBPANEL */ 4396 4397/**************************************************************************** 4398 * 4399 * Tests from John Burnell's PDCurses tester 4400 * 4401 ****************************************************************************/ 4402 4403static void 4404Continue(WINDOW *win) 4405{ 4406 noecho(); 4407 wmove(win, 10, 1); 4408 mvwaddstr(win, 10, 1, " Press any key to continue"); 4409 wrefresh(win); 4410 wGetchar(win); 4411} 4412 4413static void 4414flushinp_test(WINDOW *win) 4415/* Input test, adapted from John Burnell's PDCurses tester */ 4416{ 4417 int w, h, bx, by, sw, sh, i; 4418 4419 WINDOW *subWin; 4420 wclear(win); 4421 4422 getmaxyx(win, h, w); 4423 getbegyx(win, by, bx); 4424 sw = w / 3; 4425 sh = h / 3; 4426 if ((subWin = subwin(win, sh, sw, by + h - sh - 2, bx + w - sw - 2)) == 0) 4427 return; 4428 4429#ifdef A_COLOR 4430 if (has_colors()) { 4431 init_pair(2, COLOR_CYAN, COLOR_BLUE); 4432 wbkgd(subWin, COLOR_PAIR(2) | ' '); 4433 } 4434#endif 4435 wattrset(subWin, A_BOLD); 4436 box(subWin, ACS_VLINE, ACS_HLINE); 4437 mvwaddstr(subWin, 2, 1, "This is a subwindow"); 4438 wrefresh(win); 4439 4440 /* 4441 * This used to set 'nocbreak()'. However, Alexander Lukyanov says that 4442 * it only happened to "work" on SVr4 because that implementation does not 4443 * emulate nocbreak+noecho mode, whereas ncurses does. To get the desired 4444 * test behavior, we're using 'cbreak()', which will allow a single 4445 * character to return without needing a newline. - T.Dickey 1997/10/11. 4446 */ 4447 cbreak(); 4448 mvwaddstr(win, 0, 1, "This is a test of the flushinp() call."); 4449 4450 mvwaddstr(win, 2, 1, "Type random keys for 5 seconds."); 4451 mvwaddstr(win, 3, 1, 4452 "These should be discarded (not echoed) after the subwindow goes away."); 4453 wrefresh(win); 4454 4455 for (i = 0; i < 5; i++) { 4456 mvwprintw(subWin, 1, 1, "Time = %d", i); 4457 wrefresh(subWin); 4458 napms(1000); 4459 flushinp(); 4460 } 4461 4462 delwin(subWin); 4463 werase(win); 4464 flash(); 4465 wrefresh(win); 4466 napms(1000); 4467 4468 mvwaddstr(win, 2, 1, 4469 "If you were still typing when the window timer expired,"); 4470 mvwaddstr(win, 3, 1, 4471 "or else you typed nothing at all while it was running,"); 4472 mvwaddstr(win, 4, 1, 4473 "test was invalid. You'll see garbage or nothing at all. "); 4474 mvwaddstr(win, 6, 1, "Press a key"); 4475 wmove(win, 9, 10); 4476 wrefresh(win); 4477 echo(); 4478 wGetchar(win); 4479 flushinp(); 4480 mvwaddstr(win, 12, 0, 4481 "If you see any key other than what you typed, flushinp() is broken."); 4482 Continue(win); 4483 4484 wmove(win, 9, 10); 4485 wdelch(win); 4486 wrefresh(win); 4487 wmove(win, 12, 0); 4488 clrtoeol(); 4489 waddstr(win, 4490 "What you typed should now have been deleted; if not, wdelch() failed."); 4491 Continue(win); 4492 4493 cbreak(); 4494} 4495 4496/**************************************************************************** 4497 * 4498 * Menu test 4499 * 4500 ****************************************************************************/ 4501 4502#if USE_LIBMENU 4503 4504#define MENU_Y 8 4505#define MENU_X 8 4506 4507static int 4508menu_virtualize(int c) 4509{ 4510 if (c == '\n' || c == KEY_EXIT) 4511 return (MAX_COMMAND + 1); 4512 else if (c == 'u') 4513 return (REQ_SCR_ULINE); 4514 else if (c == 'd') 4515 return (REQ_SCR_DLINE); 4516 else if (c == 'b' || c == KEY_NPAGE) 4517 return (REQ_SCR_UPAGE); 4518 else if (c == 'f' || c == KEY_PPAGE) 4519 return (REQ_SCR_DPAGE); 4520 else if (c == 'n' || c == KEY_DOWN) 4521 return (REQ_NEXT_ITEM); 4522 else if (c == 'p' || c == KEY_UP) 4523 return (REQ_PREV_ITEM); 4524 else if (c == ' ') 4525 return (REQ_TOGGLE_ITEM); 4526 else { 4527 if (c != KEY_MOUSE) 4528 beep(); 4529 return (c); 4530 } 4531} 4532 4533static const char *animals[] = 4534{ 4535 "Lions", 4536 "Tigers", 4537 "Bears", 4538 "(Oh my!)", 4539 "Newts", 4540 "Platypi", 4541 "Lemurs", 4542 "(Oh really?!)", 4543 "Leopards", 4544 "Panthers", 4545 "Pumas", 4546 "Lions, Tigers, Bears, (Oh my!), Newts, Platypi, Lemurs", 4547 "Lions, Tigers, Bears, (Oh my!), Newts, Platypi, Lemurs, Lions, Tigers, Bears, (Oh my!), Newts, Platypi, Lemurs", 4548 (char *) 0 4549}; 4550 4551static void 4552menu_test(void) 4553{ 4554 MENU *m; 4555 ITEM *items[SIZEOF(animals)]; 4556 ITEM **ip = items; 4557 const char **ap; 4558 int mrows, mcols, c; 4559 WINDOW *menuwin; 4560 4561#ifdef NCURSES_MOUSE_VERSION 4562 mousemask(ALL_MOUSE_EVENTS, (mmask_t *) 0); 4563#endif 4564 mvaddstr(0, 0, "This is the menu test:"); 4565 mvaddstr(2, 0, " Use up and down arrow to move the select bar."); 4566 mvaddstr(3, 0, " 'n' and 'p' act like arrows."); 4567 mvaddstr(4, 0, 4568 " 'b' and 'f' scroll up/down (page), 'u' and 'd' (line)."); 4569 mvaddstr(5, 0, " Press return to exit."); 4570 refresh(); 4571 4572 for (ap = animals; *ap; ap++) 4573 *ip++ = new_item(*ap, ""); 4574 *ip = (ITEM *) 0; 4575 4576 m = new_menu(items); 4577 4578 set_menu_format(m, (SIZEOF(animals) + 1) / 2, 1); 4579 scale_menu(m, &mrows, &mcols); 4580 4581 menuwin = newwin(mrows + 2, mcols + 2, MENU_Y, MENU_X); 4582 set_menu_win(m, menuwin); 4583 keypad(menuwin, TRUE); 4584 box(menuwin, 0, 0); 4585 4586 set_menu_sub(m, derwin(menuwin, mrows, mcols, 1, 1)); 4587 4588 post_menu(m); 4589 4590 while ((c = menu_driver(m, menu_virtualize(wGetchar(menuwin)))) != E_UNKNOWN_COMMAND) { 4591 if (c == E_NOT_POSTED) 4592 break; 4593 if (c == E_REQUEST_DENIED) 4594 beep(); 4595 continue; 4596 } 4597 4598 (void) mvprintw(LINES - 2, 0, 4599 "You chose: %s\n", item_name(current_item(m))); 4600 (void) addstr("Press any key to continue..."); 4601 wGetchar(stdscr); 4602 4603 unpost_menu(m); 4604 delwin(menuwin); 4605 4606 free_menu(m); 4607 for (ip = items; *ip; ip++) 4608 free_item(*ip); 4609#ifdef NCURSES_MOUSE_VERSION 4610 mousemask(0, (mmask_t *) 0); 4611#endif 4612} 4613 4614#ifdef TRACE 4615#define T_TBL(name) { #name, name } 4616static struct { 4617 const char *name; 4618 unsigned mask; 4619} t_tbl[] = { 4620 4621 T_TBL(TRACE_DISABLE), 4622 T_TBL(TRACE_TIMES), 4623 T_TBL(TRACE_TPUTS), 4624 T_TBL(TRACE_UPDATE), 4625 T_TBL(TRACE_MOVE), 4626 T_TBL(TRACE_CHARPUT), 4627 T_TBL(TRACE_ORDINARY), 4628 T_TBL(TRACE_CALLS), 4629 T_TBL(TRACE_VIRTPUT), 4630 T_TBL(TRACE_IEVENT), 4631 T_TBL(TRACE_BITS), 4632 T_TBL(TRACE_ICALLS), 4633 T_TBL(TRACE_CCALLS), 4634 T_TBL(TRACE_DATABASE), 4635 T_TBL(TRACE_ATTRS), 4636 T_TBL(TRACE_MAXIMUM), 4637 { 4638 (char *) 0, 0 4639 } 4640}; 4641 4642static char * 4643tracetrace(unsigned tlevel) 4644{ 4645 static char *buf; 4646 int n; 4647 4648 if (buf == 0) { 4649 size_t need = 12; 4650 for (n = 0; t_tbl[n].name != 0; n++) 4651 need += strlen(t_tbl[n].name) + 2; 4652 buf = (char *) malloc(need); 4653 } 4654 sprintf(buf, "0x%02x = {", tlevel); 4655 if (tlevel == 0) { 4656 sprintf(buf + strlen(buf), "%s, ", t_tbl[0].name); 4657 } else { 4658 for (n = 1; t_tbl[n].name != 0; n++) 4659 if ((tlevel & t_tbl[n].mask) == t_tbl[n].mask) { 4660 strcat(buf, t_tbl[n].name); 4661 strcat(buf, ", "); 4662 } 4663 } 4664 if (buf[strlen(buf) - 2] == ',') 4665 buf[strlen(buf) - 2] = '\0'; 4666 return (strcat(buf, "}")); 4667} 4668 4669/* fake a dynamically reconfigurable menu using the 0th entry to deselect 4670 * the others 4671 */ 4672static int 4673run_trace_menu(MENU * m) 4674{ 4675 ITEM **items; 4676 ITEM *i, **p; 4677 4678 for (;;) { 4679 bool changed = FALSE; 4680 switch (menu_driver(m, menu_virtualize(wGetchar(menu_win(m))))) { 4681 case E_UNKNOWN_COMMAND: 4682 return FALSE; 4683 default: 4684 items = menu_items(m); 4685 i = current_item(m); 4686 if (i == items[0]) { 4687 if (item_value(i)) { 4688 for (p = items + 1; *p != 0; p++) 4689 if (item_value(*p)) { 4690 set_item_value(*p, FALSE); 4691 changed = TRUE; 4692 } 4693 } 4694 } else { 4695 for (p = items + 1; *p != 0; p++) 4696 if (item_value(*p)) { 4697 set_item_value(items[0], FALSE); 4698 changed = TRUE; 4699 break; 4700 } 4701 } 4702 if (!changed) 4703 return TRUE; 4704 } 4705 } 4706} 4707 4708static void 4709trace_set(void) 4710/* interactively set the trace level */ 4711{ 4712 MENU *m; 4713 ITEM *items[SIZEOF(t_tbl)]; 4714 ITEM **ip = items; 4715 int mrows, mcols; 4716 unsigned newtrace; 4717 int n; 4718 WINDOW *menuwin; 4719 4720 mvaddstr(0, 0, "Interactively set trace level:"); 4721 mvaddstr(2, 0, " Press space bar to toggle a selection."); 4722 mvaddstr(3, 0, " Use up and down arrow to move the select bar."); 4723 mvaddstr(4, 0, " Press return to set the trace level."); 4724 mvprintw(6, 0, "(Current trace level is %s)", tracetrace(_nc_tracing)); 4725 4726 refresh(); 4727 4728 for (n = 0; t_tbl[n].name != 0; n++) 4729 *ip++ = new_item(t_tbl[n].name, ""); 4730 *ip = (ITEM *) 0; 4731 4732 m = new_menu(items); 4733 4734 set_menu_format(m, 0, 2); 4735 scale_menu(m, &mrows, &mcols); 4736 4737 menu_opts_off(m, O_ONEVALUE); 4738 menuwin = newwin(mrows + 2, mcols + 2, MENU_Y, MENU_X); 4739 set_menu_win(m, menuwin); 4740 keypad(menuwin, TRUE); 4741 box(menuwin, 0, 0); 4742 4743 set_menu_sub(m, derwin(menuwin, mrows, mcols, 1, 1)); 4744 4745 post_menu(m); 4746 4747 for (ip = menu_items(m); *ip; ip++) { 4748 unsigned mask = t_tbl[item_index(*ip)].mask; 4749 if (mask == 0) 4750 set_item_value(*ip, _nc_tracing == 0); 4751 else if ((mask & _nc_tracing) == mask) 4752 set_item_value(*ip, TRUE); 4753 } 4754 4755 while (run_trace_menu(m)) 4756 continue; 4757 4758 newtrace = 0; 4759 for (ip = menu_items(m); *ip; ip++) 4760 if (item_value(*ip)) 4761 newtrace |= t_tbl[item_index(*ip)].mask; 4762 trace(newtrace); 4763 _tracef("trace level interactively set to %s", tracetrace(_nc_tracing)); 4764 4765 (void) mvprintw(LINES - 2, 0, 4766 "Trace level is %s\n", tracetrace(_nc_tracing)); 4767 (void) addstr("Press any key to continue..."); 4768 wGetchar(stdscr); 4769 4770 unpost_menu(m); 4771 delwin(menuwin); 4772 4773 free_menu(m); 4774 for (ip = items; *ip; ip++) 4775 free_item(*ip); 4776} 4777#endif /* TRACE */ 4778#endif /* USE_LIBMENU */ 4779 4780/**************************************************************************** 4781 * 4782 * Forms test 4783 * 4784 ****************************************************************************/ 4785#if USE_LIBFORM 4786static FIELD * 4787make_label(int frow, int fcol, NCURSES_CONST char *label) 4788{ 4789 FIELD *f = new_field(1, (int) strlen(label), frow, fcol, 0, 0); 4790 4791 if (f) { 4792 set_field_buffer(f, 0, label); 4793 set_field_opts(f, (int) (field_opts(f) & ~O_ACTIVE)); 4794 } 4795 return (f); 4796} 4797 4798static FIELD * 4799make_field(int frow, int fcol, int rows, int cols, bool secure) 4800{ 4801 FIELD *f = new_field(rows, cols, frow, fcol, 0, secure ? 1 : 0); 4802 4803 if (f) { 4804 set_field_back(f, A_UNDERLINE); 4805 set_field_userptr(f, (void *) 0); 4806 } 4807 return (f); 4808} 4809 4810static void 4811display_form(FORM * f) 4812{ 4813 WINDOW *w; 4814 int rows, cols; 4815 4816 scale_form(f, &rows, &cols); 4817 4818 if ((w = newwin(rows + 2, cols + 4, 0, 0)) != (WINDOW *) 0) { 4819 set_form_win(f, w); 4820 set_form_sub(f, derwin(w, rows, cols, 1, 2)); 4821 box(w, 0, 0); 4822 keypad(w, TRUE); 4823 } 4824 4825 if (post_form(f) != E_OK) 4826 wrefresh(w); 4827} 4828 4829static void 4830erase_form(FORM * f) 4831{ 4832 WINDOW *w = form_win(f); 4833 WINDOW *s = form_sub(f); 4834 4835 unpost_form(f); 4836 werase(w); 4837 wrefresh(w); 4838 delwin(s); 4839 delwin(w); 4840} 4841 4842static int 4843edit_secure(FIELD * me, int c) 4844{ 4845 int rows, cols, frow, fcol, nrow, nbuf; 4846 4847 if (field_info(me, &rows, &cols, &frow, &fcol, &nrow, &nbuf) == E_OK 4848 && nbuf > 0) { 4849 char temp[80]; 4850 long len; 4851 4852 strcpy(temp, field_buffer(me, 1)); 4853 len = (long) (char *) field_userptr(me); 4854 if (c <= KEY_MAX) { 4855 if (isgraph(c) && (len + 1) < (int) sizeof(temp)) { 4856 temp[len++] = c; 4857 temp[len] = 0; 4858 set_field_buffer(me, 1, temp); 4859 c = '*'; 4860 } else { 4861 c = 0; 4862 } 4863 } else { 4864 switch (c) { 4865 case REQ_BEG_FIELD: 4866 case REQ_CLR_EOF: 4867 case REQ_CLR_EOL: 4868 case REQ_DEL_LINE: 4869 case REQ_DEL_WORD: 4870 case REQ_DOWN_CHAR: 4871 case REQ_END_FIELD: 4872 case REQ_INS_CHAR: 4873 case REQ_INS_LINE: 4874 case REQ_LEFT_CHAR: 4875 case REQ_NEW_LINE: 4876 case REQ_NEXT_WORD: 4877 case REQ_PREV_WORD: 4878 case REQ_RIGHT_CHAR: 4879 case REQ_UP_CHAR: 4880 c = 0; /* we don't want to do inline editing */ 4881 break; 4882 case REQ_CLR_FIELD: 4883 if (len) { 4884 temp[0] = 0; 4885 set_field_buffer(me, 1, temp); 4886 } 4887 break; 4888 case REQ_DEL_CHAR: 4889 case REQ_DEL_PREV: 4890 if (len) { 4891 temp[--len] = 0; 4892 set_field_buffer(me, 1, temp); 4893 } 4894 break; 4895 } 4896 } 4897 set_field_userptr(me, (void *) len); 4898 } 4899 return c; 4900} 4901 4902static int 4903form_virtualize(FORM * f, WINDOW *w) 4904{ 4905 static const struct { 4906 int code; 4907 int result; 4908 } lookup[] = { 4909 { 4910 CTRL('A'), REQ_NEXT_CHOICE 4911 }, 4912 { 4913 CTRL('B'), REQ_PREV_WORD 4914 }, 4915 { 4916 CTRL('C'), REQ_CLR_EOL 4917 }, 4918 { 4919 CTRL('D'), REQ_DOWN_FIELD 4920 }, 4921 { 4922 CTRL('E'), REQ_END_FIELD 4923 }, 4924 { 4925 CTRL('F'), REQ_NEXT_PAGE 4926 }, 4927 { 4928 CTRL('G'), REQ_DEL_WORD 4929 }, 4930 { 4931 CTRL('H'), REQ_DEL_PREV 4932 }, 4933 { 4934 CTRL('I'), REQ_INS_CHAR 4935 }, 4936 { 4937 CTRL('K'), REQ_CLR_EOF 4938 }, 4939 { 4940 CTRL('L'), REQ_LEFT_FIELD 4941 }, 4942 { 4943 CTRL('M'), REQ_NEW_LINE 4944 }, 4945 { 4946 CTRL('N'), REQ_NEXT_FIELD 4947 }, 4948 { 4949 CTRL('O'), REQ_INS_LINE 4950 }, 4951 { 4952 CTRL('P'), REQ_PREV_FIELD 4953 }, 4954 { 4955 CTRL('R'), REQ_RIGHT_FIELD 4956 }, 4957 { 4958 CTRL('S'), REQ_BEG_FIELD 4959 }, 4960 { 4961 CTRL('U'), REQ_UP_FIELD 4962 }, 4963 { 4964 CTRL('V'), REQ_DEL_CHAR 4965 }, 4966 { 4967 CTRL('W'), REQ_NEXT_WORD 4968 }, 4969 { 4970 CTRL('X'), REQ_CLR_FIELD 4971 }, 4972 { 4973 CTRL('Y'), REQ_DEL_LINE 4974 }, 4975 { 4976 CTRL('Z'), REQ_PREV_CHOICE 4977 }, 4978 { 4979 ESCAPE, MAX_FORM_COMMAND + 1 4980 }, 4981 { 4982 KEY_BACKSPACE, REQ_DEL_PREV 4983 }, 4984 { 4985 KEY_DOWN, REQ_DOWN_CHAR 4986 }, 4987 { 4988 KEY_END, REQ_LAST_FIELD 4989 }, 4990 { 4991 KEY_HOME, REQ_FIRST_FIELD 4992 }, 4993 { 4994 KEY_LEFT, REQ_LEFT_CHAR 4995 }, 4996 { 4997 KEY_LL, REQ_LAST_FIELD 4998 }, 4999 { 5000 KEY_NEXT, REQ_NEXT_FIELD 5001 }, 5002 { 5003 KEY_NPAGE, REQ_NEXT_PAGE 5004 }, 5005 { 5006 KEY_PPAGE, REQ_PREV_PAGE 5007 }, 5008 { 5009 KEY_PREVIOUS, REQ_PREV_FIELD 5010 }, 5011 { 5012 KEY_RIGHT, REQ_RIGHT_CHAR 5013 }, 5014 { 5015 KEY_UP, REQ_UP_CHAR 5016 }, 5017 { 5018 QUIT, MAX_FORM_COMMAND + 1 5019 } 5020 }; 5021 5022 static int mode = REQ_INS_MODE; 5023 int c = wGetchar(w); 5024 unsigned n; 5025 FIELD *me = current_field(f); 5026 bool current = TRUE; 5027 5028 if (c == CTRL(']')) { 5029 if (mode == REQ_INS_MODE) { 5030 mode = REQ_OVL_MODE; 5031 } else { 5032 mode = REQ_INS_MODE; 5033 } 5034 c = mode; 5035 } else { 5036 for (n = 0; n < SIZEOF(lookup); n++) { 5037 if (lookup[n].code == c) { 5038 c = lookup[n].result; 5039 break; 5040 } 5041 } 5042 } 5043 mvprintw(0, COLS - 6, "(%s)", mode == REQ_INS_MODE ? "INS" : "OVL"); 5044 5045 /* 5046 * Force the field that the user is typing into to be in reverse video, 5047 * while the other fields are shown underlined. 5048 */ 5049 switch (c) { 5050 case REQ_BEG_FIELD: 5051 case REQ_CLR_EOF: 5052 case REQ_CLR_EOL: 5053 case REQ_CLR_FIELD: 5054 case REQ_DEL_CHAR: 5055 case REQ_DEL_LINE: 5056 case REQ_DEL_PREV: 5057 case REQ_DEL_WORD: 5058 case REQ_END_FIELD: 5059 case REQ_INS_CHAR: 5060 case REQ_INS_LINE: 5061 case REQ_LEFT_CHAR: 5062 case REQ_LEFT_FIELD: 5063 case REQ_NEXT_WORD: 5064 case REQ_RIGHT_CHAR: 5065 current = TRUE; 5066 break; 5067 default: 5068 current = (c < KEY_MAX); 5069 break; 5070 } 5071 if (current) { 5072 c = edit_secure(me, c); 5073 set_field_back(me, A_REVERSE); 5074 } else { 5075 c = edit_secure(me, c); 5076 set_field_back(me, A_UNDERLINE); 5077 } 5078 return c; 5079} 5080 5081static int 5082my_form_driver(FORM * form, int c) 5083{ 5084 if (c == (MAX_FORM_COMMAND + 1) 5085 && form_driver(form, REQ_VALIDATION) == E_OK) 5086 return (TRUE); 5087 else { 5088 beep(); 5089 return (FALSE); 5090 } 5091} 5092 5093/* 5094 * Allow a middle initial, optionally with a '.' to end it. 5095 */ 5096static bool 5097mi_field_check(FIELD * fld, const void *data GCC_UNUSED) 5098{ 5099 char *s = field_buffer(fld, 0); 5100 int state = 0; 5101 int n; 5102 5103 for (n = 0; s[n] != '\0'; ++n) { 5104 switch (state) { 5105 case 0: 5106 if (s[n] == '.') { 5107 if (n != 1) 5108 return FALSE; 5109 state = 2; 5110 } else if (isspace(UChar(s[n]))) { 5111 state = 2; 5112 } 5113 break; 5114 case 2: 5115 if (!isspace(UChar(s[n]))) 5116 return FALSE; 5117 break; 5118 } 5119 } 5120 5121 /* force the form to display a leading capital */ 5122 if (islower(UChar(s[0]))) { 5123 s[0] = toupper(UChar(s[0])); 5124 set_field_buffer(fld, 0, s); 5125 } 5126 return TRUE; 5127} 5128 5129static bool 5130mi_char_check(int ch, const void *data GCC_UNUSED) 5131{ 5132 return ((isalpha(ch) || ch == '.') ? TRUE : FALSE); 5133} 5134 5135/* 5136 * Passwords should be at least 6 characters. 5137 */ 5138static bool 5139pw_field_check(FIELD * fld, const void *data GCC_UNUSED) 5140{ 5141 char *s = field_buffer(fld, 0); 5142 int n; 5143 5144 for (n = 0; s[n] != '\0'; ++n) { 5145 if (isspace(UChar(s[n]))) { 5146 if (n < 6) 5147 return FALSE; 5148 } 5149 } 5150 return TRUE; 5151} 5152 5153static bool 5154pw_char_check(int ch, const void *data GCC_UNUSED) 5155{ 5156 return (isgraph(ch) ? TRUE : FALSE); 5157} 5158 5159static void 5160demo_forms(void) 5161{ 5162 WINDOW *w; 5163 FORM *form; 5164 FIELD *f[12], *secure; 5165 FIELDTYPE *fty_middle = new_fieldtype(mi_field_check, mi_char_check); 5166 FIELDTYPE *fty_passwd = new_fieldtype(pw_field_check, pw_char_check); 5167 int finished = 0, c; 5168 unsigned n = 0; 5169 5170 move(18, 0); 5171 addstr("Defined edit/traversal keys: ^Q/ESC- exit form\n"); 5172 addstr("^N -- go to next field ^P -- go to previous field\n"); 5173 addstr("Home -- go to first field End -- go to last field\n"); 5174 addstr("^L -- go to field to left ^R -- go to field to right\n"); 5175 addstr("^U -- move upward to field ^D -- move downward to field\n"); 5176 addstr("^W -- go to next word ^B -- go to previous word\n"); 5177 addstr("^S -- go to start of field ^E -- go to end of field\n"); 5178 addstr("^H -- delete previous char ^Y -- delete line\n"); 5179 addstr("^G -- delete current word ^C -- clear to end of line\n"); 5180 addstr("^K -- clear to end of field ^X -- clear field\n"); 5181 addstr("Arrow keys move within a field as you would expect. ^] toggles overlay mode."); 5182 5183 mvaddstr(4, 57, "Forms Entry Test"); 5184 5185 refresh(); 5186 5187 /* describe the form */ 5188 f[n++] = make_label(0, 15, "Sample Form"); 5189 5190 f[n++] = make_label(2, 0, "Last Name"); 5191 f[n++] = make_field(3, 0, 1, 18, FALSE); 5192 set_field_type(f[n - 1], TYPE_ALPHA, 1); 5193 5194 f[n++] = make_label(2, 20, "First Name"); 5195 f[n++] = make_field(3, 20, 1, 12, FALSE); 5196 set_field_type(f[n - 1], TYPE_ALPHA, 1); 5197 5198 f[n++] = make_label(2, 34, "Middle Name"); 5199 f[n++] = make_field(3, 34, 1, 12, FALSE); 5200 set_field_type(f[n - 1], fty_middle); 5201 5202 f[n++] = make_label(5, 0, "Comments"); 5203 f[n++] = make_field(6, 0, 4, 46, FALSE); 5204 5205 f[n++] = make_label(5, 20, "Password:"); 5206 secure = 5207 f[n++] = make_field(5, 30, 1, 9, TRUE); 5208 set_field_type(f[n - 1], fty_passwd); 5209 f[n++] = (FIELD *) 0; 5210 5211 form = new_form(f); 5212 5213 display_form(form); 5214 5215 w = form_win(form); 5216 raw(); 5217 nonl(); /* lets us read ^M's */ 5218 while (!finished) { 5219 switch (form_driver(form, c = form_virtualize(form, w))) { 5220 case E_OK: 5221 mvaddstr(5, 57, field_buffer(secure, 1)); 5222 clrtoeol(); 5223 refresh(); 5224 break; 5225 case E_UNKNOWN_COMMAND: 5226 finished = my_form_driver(form, c); 5227 break; 5228 default: 5229 beep(); 5230 break; 5231 } 5232 } 5233 5234 erase_form(form); 5235 5236 free_form(form); 5237 for (c = 0; f[c] != 0; c++) 5238 free_field(f[c]); 5239 free_fieldtype(fty_middle); 5240 free_fieldtype(fty_passwd); 5241 noraw(); 5242 nl(); 5243} 5244#endif /* USE_LIBFORM */ 5245 5246/**************************************************************************** 5247 * 5248 * Overlap test 5249 * 5250 ****************************************************************************/ 5251 5252static void 5253fillwin(WINDOW *win, char ch) 5254{ 5255 int y, x; 5256 int y1, x1; 5257 5258 getmaxyx(win, y1, x1); 5259 for (y = 0; y < y1; y++) { 5260 wmove(win, y, 0); 5261 for (x = 0; x < x1; x++) 5262 waddch(win, UChar(ch)); 5263 } 5264} 5265 5266static void 5267crosswin(WINDOW *win, char ch) 5268{ 5269 int y, x; 5270 int y1, x1; 5271 5272 getmaxyx(win, y1, x1); 5273 for (y = 0; y < y1; y++) { 5274 for (x = 0; x < x1; x++) 5275 if (((x > (x1 - 1) / 3) && (x <= (2 * (x1 - 1)) / 3)) 5276 || (((y > (y1 - 1) / 3) && (y <= (2 * (y1 - 1)) / 3)))) { 5277 wmove(win, y, x); 5278 waddch(win, UChar(ch)); 5279 } 5280 } 5281} 5282 5283static void 5284overlap_test(void) 5285/* test effects of overlapping windows */ 5286{ 5287 int ch; 5288 5289 WINDOW *win1 = newwin(9, 20, 3, 3); 5290 WINDOW *win2 = newwin(9, 20, 9, 16); 5291 5292 raw(); 5293 refresh(); 5294 move(0, 0); 5295 printw("This test shows the behavior of wnoutrefresh() with respect to\n"); 5296 printw("the shared region of two overlapping windows A and B. The cross\n"); 5297 printw("pattern in each window does not overlap the other.\n"); 5298 5299 move(18, 0); 5300 printw("a = refresh A, then B, then doupdate. b = refresh B, then A, then doupdaute\n"); 5301 printw("c = fill window A with letter A. d = fill window B with letter B.\n"); 5302 printw("e = cross pattern in window A. f = cross pattern in window B.\n"); 5303 printw("g = clear window A. h = clear window B.\n"); 5304 printw("i = overwrite A onto B. j = overwrite B onto A.\n"); 5305 printw("^Q/ESC = terminate test."); 5306 5307 while ((ch = Getchar()) != QUIT && ch != ESCAPE) 5308 switch (ch) { 5309 case 'a': /* refresh window A first, then B */ 5310 wnoutrefresh(win1); 5311 wnoutrefresh(win2); 5312 doupdate(); 5313 break; 5314 5315 case 'b': /* refresh window B first, then A */ 5316 wnoutrefresh(win2); 5317 wnoutrefresh(win1); 5318 doupdate(); 5319 break; 5320 5321 case 'c': /* fill window A so it's visible */ 5322 fillwin(win1, 'A'); 5323 break; 5324 5325 case 'd': /* fill window B so it's visible */ 5326 fillwin(win2, 'B'); 5327 break; 5328 5329 case 'e': /* cross test pattern in window A */ 5330 crosswin(win1, 'A'); 5331 break; 5332 5333 case 'f': /* cross test pattern in window A */ 5334 crosswin(win2, 'B'); 5335 break; 5336 5337 case 'g': /* clear window A */ 5338 wclear(win1); 5339 wmove(win1, 0, 0); 5340 break; 5341 5342 case 'h': /* clear window B */ 5343 wclear(win2); 5344 wmove(win2, 0, 0); 5345 break; 5346 5347 case 'i': /* overwrite A onto B */ 5348 overwrite(win1, win2); 5349 break; 5350 5351 case 'j': /* overwrite B onto A */ 5352 overwrite(win2, win1); 5353 break; 5354 } 5355 5356 delwin(win2); 5357 delwin(win1); 5358 erase(); 5359 endwin(); 5360} 5361 5362/**************************************************************************** 5363 * 5364 * Main sequence 5365 * 5366 ****************************************************************************/ 5367 5368static bool 5369do_single_test(const char c) 5370/* perform a single specified test */ 5371{ 5372 switch (c) { 5373 case 'a': 5374 getch_test(); 5375 break; 5376 5377#if USE_WIDEC_SUPPORT 5378 case 'A': 5379 get_wch_test(); 5380 break; 5381#endif 5382 5383 case 'b': 5384 attr_test(); 5385 break; 5386 5387#if USE_WIDEC_SUPPORT 5388 case 'B': 5389 wide_attr_test(); 5390 break; 5391#endif 5392 5393 case 'c': 5394 if (!has_colors()) 5395 Cannot("does not support color."); 5396 else 5397 color_test(); 5398 break; 5399 5400#if USE_WIDEC_SUPPORT 5401 case 'C': 5402 if (!has_colors()) 5403 Cannot("does not support color."); 5404 else 5405 wide_color_test(); 5406 break; 5407#endif 5408 5409 case 'd': 5410 if (!has_colors()) 5411 Cannot("does not support color."); 5412 else if (!can_change_color()) 5413 Cannot("has hardwired color values."); 5414 else 5415 color_edit(); 5416 break; 5417 5418 case 'e': 5419 slk_test(); 5420 break; 5421 5422#if USE_WIDEC_SUPPORT 5423 case 'E': 5424 wide_slk_test(); 5425 break; 5426#endif 5427 case 'f': 5428 acs_display(); 5429 break; 5430 5431#if USE_WIDEC_SUPPORT 5432 case 'F': 5433 wide_acs_display(); 5434 break; 5435#endif 5436 5437#if USE_LIBPANEL 5438 case 'o': 5439 demo_panels(); 5440 break; 5441#endif 5442 5443 case 'g': 5444 acs_and_scroll(); 5445 break; 5446 5447 case 'i': 5448 flushinp_test(stdscr); 5449 break; 5450 5451 case 'k': 5452 test_sgr_attributes(); 5453 break; 5454 5455#if USE_LIBMENU 5456 case 'm': 5457 menu_test(); 5458 break; 5459#endif 5460 5461#if USE_LIBPANEL 5462 case 'p': 5463 demo_pad(); 5464 break; 5465#endif 5466 5467#if USE_LIBFORM 5468 case 'r': 5469 demo_forms(); 5470 break; 5471#endif 5472 5473 case 's': 5474 overlap_test(); 5475 break; 5476 5477#if USE_LIBMENU && defined(TRACE) 5478 case 't': 5479 trace_set(); 5480 break; 5481#endif 5482 5483 case '?': 5484 break; 5485 5486 default: 5487 return FALSE; 5488 } 5489 5490 return TRUE; 5491} 5492 5493static void 5494usage(void) 5495{ 5496 static const char *const tbl[] = 5497 { 5498 "Usage: ncurses [options]" 5499 ,"" 5500 ,"Options:" 5501#ifdef NCURSES_VERSION 5502 ," -a f,b set default-colors (assumed white-on-black)" 5503 ," -d use default-colors if terminal supports them" 5504#endif 5505 ," -e fmt specify format for soft-keys test (e)" 5506 ," -f rip-off footer line (can repeat)" 5507 ," -h rip-off header line (can repeat)" 5508 ," -p file rgb values to use in 'd' rather than ncurses's builtin" 5509#if USE_LIBPANEL 5510 ," -s msec specify nominal time for panel-demo (default: 1, to hold)" 5511#endif 5512#ifdef TRACE 5513 ," -t mask specify default trace-level (may toggle with ^T)" 5514#endif 5515 }; 5516 size_t n; 5517 for (n = 0; n < SIZEOF(tbl); n++) 5518 fprintf(stderr, "%s\n", tbl[n]); 5519 ExitProgram(EXIT_FAILURE); 5520} 5521 5522static void 5523set_terminal_modes(void) 5524{ 5525 noraw(); 5526 cbreak(); 5527 noecho(); 5528 scrollok(stdscr, TRUE); 5529 idlok(stdscr, TRUE); 5530 keypad(stdscr, TRUE); 5531} 5532 5533#ifdef SIGUSR1 5534static RETSIGTYPE 5535announce_sig(int sig) 5536{ 5537 (void) fprintf(stderr, "Handled signal %d\r\n", sig); 5538} 5539#endif 5540 5541static int 5542rip_footer(WINDOW *win, int cols) 5543{ 5544 wbkgd(win, A_REVERSE); 5545 werase(win); 5546 wmove(win, 0, 0); 5547 wprintw(win, "footer: %d columns", cols); 5548 wnoutrefresh(win); 5549 return OK; 5550} 5551 5552static int 5553rip_header(WINDOW *win, int cols) 5554{ 5555 wbkgd(win, A_REVERSE); 5556 werase(win); 5557 wmove(win, 0, 0); 5558 wprintw(win, "header: %d columns", cols); 5559 wnoutrefresh(win); 5560 return OK; 5561} 5562 5563static void 5564main_menu(bool top) 5565{ 5566 int command; 5567 5568 do { 5569 (void) puts("This is the ncurses main menu"); 5570 (void) puts("a = keyboard and mouse input test"); 5571#if USE_WIDEC_SUPPORT 5572 (void) puts("A = wide-character keyboard and mouse input test"); 5573#endif 5574 (void) puts("b = character attribute test"); 5575#if USE_WIDEC_SUPPORT 5576 (void) puts("B = wide-character attribute test"); 5577#endif 5578 (void) puts("c = color test pattern"); 5579#if USE_WIDEC_SUPPORT 5580 (void) puts("C = color test pattern using wide-character calls"); 5581#endif 5582 if (top) 5583 (void) puts("d = edit RGB color values"); 5584 (void) puts("e = exercise soft keys"); 5585#if USE_WIDEC_SUPPORT 5586 (void) puts("E = exercise soft keys using wide-characters"); 5587#endif 5588 (void) puts("f = display ACS characters"); 5589#if USE_WIDEC_SUPPORT 5590 (void) puts("F = display Wide-ACS characters"); 5591#endif 5592 (void) puts("g = display windows and scrolling"); 5593 (void) puts("i = test of flushinp()"); 5594 (void) puts("k = display character attributes"); 5595#if USE_LIBMENU 5596 (void) puts("m = menu code test"); 5597#endif 5598#if USE_LIBPANEL 5599 (void) puts("o = exercise panels library"); 5600 (void) puts("p = exercise pad features"); 5601 (void) puts("q = quit"); 5602#endif 5603#if USE_LIBFORM 5604 (void) puts("r = exercise forms code"); 5605#endif 5606 (void) puts("s = overlapping-refresh test"); 5607#if USE_LIBMENU && defined(TRACE) 5608 (void) puts("t = set trace level"); 5609#endif 5610 (void) puts("? = repeat this command summary"); 5611 5612 (void) fputs("> ", stdout); 5613 (void) fflush(stdout); /* necessary under SVr4 curses */ 5614 5615 /* 5616 * This used to be an 'fgets()' call. However (on Linux, at least) 5617 * mixing stream I/O and 'read()' (used in the library) causes the 5618 * input stream to be flushed when switching between the two. 5619 */ 5620 command = 0; 5621 for (;;) { 5622 char ch; 5623 if (read(fileno(stdin), &ch, 1) <= 0) { 5624 if (command == 0) 5625 command = 'q'; 5626 break; 5627 } else if (command == 0 && !isspace(UChar(ch))) { 5628 command = ch; 5629 } else if (ch == '\n' || ch == '\r') { 5630 if ((command == 'd') && !top) { 5631 (void) fputs("Do not nest test-d\n", stdout); 5632 command = 0; 5633 } 5634 if (command != 0) 5635 break; 5636 (void) fputs("> ", stdout); 5637 (void) fflush(stdout); 5638 } 5639 } 5640 5641 if (do_single_test(command)) { 5642 /* 5643 * This may be overkill; it's intended to reset everything back 5644 * to the initial terminal modes so that tests don't get in 5645 * each other's way. 5646 */ 5647 flushinp(); 5648 set_terminal_modes(); 5649 reset_prog_mode(); 5650 clear(); 5651 refresh(); 5652 endwin(); 5653 if (command == '?') { 5654 (void) puts("This is the ncurses capability tester."); 5655 (void) 5656 puts("You may select a test from the main menu by typing the"); 5657 (void) 5658 puts("key letter of the choice (the letter to left of the =)"); 5659 (void) 5660 puts("at the > prompt. The commands `x' or `q' will exit."); 5661 } 5662 continue; 5663 } 5664 } while 5665 (command != 'q'); 5666} 5667 5668/*+------------------------------------------------------------------------- 5669 main(argc,argv) 5670--------------------------------------------------------------------------*/ 5671 5672#define okCOLOR(n) ((n) >= 0 && (n) < max_colors) 5673#define okRGB(n) ((n) >= 0 && (n) <= 1000) 5674 5675int 5676main(int argc, char *argv[]) 5677{ 5678 int c; 5679 int my_e_param = 1; 5680#ifdef NCURSES_VERSION 5681 int default_fg = COLOR_WHITE; 5682 int default_bg = COLOR_BLACK; 5683 bool assumed_colors = FALSE; 5684 bool default_colors = FALSE; 5685#endif 5686 char *palette_file = 0; 5687 5688 setlocale(LC_ALL, ""); 5689 5690 while ((c = getopt(argc, argv, "a:de:fhp:s:t:")) != EOF) { 5691 switch (c) { 5692#ifdef NCURSES_VERSION 5693 case 'a': 5694 assumed_colors = TRUE; 5695 sscanf(optarg, "%d,%d", &default_fg, &default_bg); 5696 break; 5697 case 'd': 5698 default_colors = TRUE; 5699 break; 5700#endif 5701 case 'e': 5702 my_e_param = atoi(optarg); 5703#ifdef NCURSES_VERSION 5704 if (my_e_param > 3) /* allow extended layouts */ 5705 usage(); 5706#else 5707 if (my_e_param > 1) 5708 usage(); 5709#endif 5710 break; 5711 case 'f': 5712 ripoffline(-1, rip_footer); 5713 break; 5714 case 'h': 5715 ripoffline(1, rip_header); 5716 break; 5717 case 'p': 5718 palette_file = optarg; 5719 break; 5720#if USE_LIBPANEL 5721 case 's': 5722 nap_msec = atol(optarg); 5723 break; 5724#endif 5725#ifdef TRACE 5726 case 't': 5727 save_trace = strtol(optarg, 0, 0); 5728 break; 5729#endif 5730 default: 5731 usage(); 5732 } 5733 } 5734 5735 /* 5736 * If there's no menus (unlikely for ncurses!), then we'll have to set 5737 * tracing on initially, just in case the user wants to test something that 5738 * doesn't involve wGetchar. 5739 */ 5740#ifdef TRACE 5741 /* enable debugging */ 5742#if !USE_LIBMENU 5743 trace(save_trace); 5744#else 5745 if (!isatty(fileno(stdin))) 5746 trace(save_trace); 5747#endif /* USE_LIBMENU */ 5748#endif /* TRACE */ 5749 5750 /* tell it we're going to play with soft keys */ 5751 slk_init(my_e_param); 5752 5753#ifdef SIGUSR1 5754 /* set up null signal catcher so we can see what interrupts to getch do */ 5755 signal(SIGUSR1, announce_sig); 5756#endif 5757 5758 /* we must initialize the curses data structure only once */ 5759 initscr(); 5760 bkgdset(BLANK); 5761 5762 /* tests, in general, will want these modes */ 5763 if (has_colors()) { 5764 start_color(); 5765#ifdef NCURSES_VERSION_PATCH 5766 max_colors = COLORS; /* was > 16 ? 16 : COLORS */ 5767#if HAVE_USE_DEFAULT_COLORS 5768 if (default_colors) { 5769 use_default_colors(); 5770 min_colors = -1; 5771 } 5772#if NCURSES_VERSION_PATCH >= 20000708 5773 else if (assumed_colors) 5774 assume_default_colors(default_fg, default_bg); 5775#endif 5776#endif 5777#else /* normal SVr4 curses */ 5778 max_colors = COLORS; /* was > 8 ? 8 : COLORS */ 5779#endif 5780 max_pairs = COLOR_PAIRS; /* was > 256 ? 256 : COLOR_PAIRS */ 5781 5782 if (can_change_color()) { 5783 all_colors = (RGB_DATA *) malloc(max_colors * sizeof(RGB_DATA)); 5784 for (c = 0; c < max_colors; ++c) { 5785 color_content(c, 5786 &all_colors[c].red, 5787 &all_colors[c].green, 5788 &all_colors[c].blue); 5789 } 5790 if (palette_file != 0) { 5791 FILE *fp = fopen(palette_file, "r"); 5792 if (fp != 0) { 5793 char buffer[BUFSIZ]; 5794 int red, green, blue; 5795 int scale = 1000; 5796 while (fgets(buffer, sizeof(buffer), fp) != 0) { 5797 if (sscanf(buffer, "scale:%d", &c) == 1) { 5798 scale = c; 5799 } else if (sscanf(buffer, "%d:%d %d %d", 5800 &c, 5801 &red, 5802 &green, 5803 &blue) == 4 5804 && okCOLOR(c) 5805 && okRGB(red) 5806 && okRGB(green) 5807 && okRGB(blue)) { 5808 all_colors[c].red = (red * 1000) / scale; 5809 all_colors[c].green = (green * 1000) / scale; 5810 all_colors[c].blue = (blue * 1000) / scale; 5811 } 5812 } 5813 fclose(fp); 5814 } 5815 } 5816 } 5817 } 5818 set_terminal_modes(); 5819 def_prog_mode(); 5820 5821 /* 5822 * Return to terminal mode, so we're guaranteed of being able to 5823 * select terminal commands even if the capabilities are wrong. 5824 */ 5825 endwin(); 5826 5827#if HAVE_CURSES_VERSION 5828 (void) printf("Welcome to %s. Press ? for help.\n", curses_version()); 5829#elif defined(NCURSES_VERSION_MAJOR) && defined(NCURSES_VERSION_MINOR) && defined(NCURSES_VERSION_PATCH) 5830 (void) printf("Welcome to ncurses %d.%d.%d. Press ? for help.\n", 5831 NCURSES_VERSION_MAJOR, 5832 NCURSES_VERSION_MINOR, 5833 NCURSES_VERSION_PATCH); 5834#else 5835 (void) puts("Welcome to ncurses. Press ? for help."); 5836#endif 5837 5838 main_menu(TRUE); 5839 5840 ExitProgram(EXIT_SUCCESS); 5841} 5842 5843/* ncurses.c ends here */ 5844