1/**************************************************************************** 2 * Copyright (c) 2007,2008 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 * $Id: demo_panels.c,v 1.33 2008/08/04 13:33:48 tom Exp $ 30 * 31 * Demonstrate a variety of functions from the panel library. 32 */ 33 34#include <test.priv.h> 35 36#if USE_LIBPANEL 37 38#include <panel.h> 39 40#define LAST_POS '@' 41#define TEMP_POS '>' 42 43typedef void (*InitPanel) (void); 44typedef void (*FillPanel) (PANEL *); 45 46static bool use_colors = FALSE; 47static bool unboxed = FALSE; 48static FILE *log_in; 49static FILE *log_out; 50 51static void 52close_input(void) 53{ 54 if (log_in != 0) { 55 fclose(log_in); 56 log_in = 0; 57 } 58} 59 60static void 61close_output(void) 62{ 63 if (log_out != 0) { 64 fclose(log_out); 65 log_out = 0; 66 } 67} 68 69static WINDOW * 70statusline(void) 71{ 72 WINDOW *result = stdscr; 73 74 wmove(result, LINES - 1, 0); 75 wclrtoeol(result); 76 return result; 77} 78 79static void 80pflush(void) 81{ 82 update_panels(); 83 doupdate(); 84} 85 86static void 87saywhat(NCURSES_CONST char *text) 88{ 89 WINDOW *win = statusline(); 90 if (text != 0 && *text != '\0') { 91 waddstr(win, text); 92 waddstr(win, "; "); 93 } 94 waddstr(win, "press any key to continue"); 95} 96 97static void 98show_position(NCURSES_CONST char *text, 99 NCURSES_CONST char *also, 100 int which, 101 int ypos, 102 int xpos) 103{ 104 WINDOW *win = statusline(); 105 106 wprintw(win, "%s for panel %d now %d,%d%s", text, which, ypos, xpos, also); 107 wmove(stdscr, ypos, xpos); 108} 109 110static int 111get_position(NCURSES_CONST char *text, 112 NCURSES_CONST char *also, 113 int which, 114 int *xpos, 115 int *ypos) 116{ 117 int result = 0; 118 int x1, y1; 119 char cmd; 120 WINDOW *win; 121 122 getyx(stdscr, y1, x1); 123 win = statusline(); 124 125 show_position(text, also, which, y1, x1); 126 127 if (log_in != 0) { 128 if (fscanf(log_in, "%c%d,%d\n", &cmd, &y1, &x1) == 3) { 129 switch (cmd) { 130 case LAST_POS: 131 result = 1; 132 (void) wgetch(stdscr); 133 break; 134 case TEMP_POS: 135 result = 0; 136 wrefresh(stdscr); 137 napms(100); 138 break; 139 default: 140 result = -1; 141 break; 142 } 143 } else { 144 result = -1; 145 } 146 } else { 147 148 switch (wgetch(stdscr)) { 149 case QUIT: 150 case ESCAPE: 151 case ERR: 152 result = -1; 153 break; 154 case ' ': 155 result = 1; 156 break; 157 case KEY_UP: 158 if (y1 > 0) { 159 --y1; 160 } else { 161 beep(); 162 } 163 break; 164 case KEY_DOWN: 165 if (y1 < getmaxy(stdscr)) { 166 ++y1; 167 } else { 168 beep(); 169 } 170 break; 171 case KEY_LEFT: 172 if (x1 > 0) { 173 --x1; 174 } else { 175 beep(); 176 } 177 break; 178 case KEY_RIGHT: 179 if (x1 < getmaxx(stdscr)) { 180 ++x1; 181 } else { 182 beep(); 183 } 184 break; 185 } 186 } 187 188 wmove(stdscr, y1, x1); 189 *ypos = y1; 190 *xpos = x1; 191 192 if (result >= 0) { 193 if (log_out) 194 fprintf(log_out, "%c%d,%d\n", 195 ((result > 0) 196 ? LAST_POS 197 : TEMP_POS), 198 y1, x1); 199 } 200 return result; 201} 202 203static PANEL * 204mkpanel(short color, int rows, int cols, int tly, int tlx) 205{ 206 WINDOW *win; 207 PANEL *pan = 0; 208 char *userdata = typeMalloc(char, 3); 209 210 if ((win = newwin(rows, cols, tly, tlx)) != 0) { 211 keypad(win, TRUE); 212 if ((pan = new_panel(win)) == 0) { 213 delwin(win); 214 } else if (use_colors) { 215 short fg = (short) ((color == COLOR_BLUE) 216 ? COLOR_WHITE 217 : COLOR_BLACK); 218 short bg = color; 219 220 init_pair(color, fg, bg); 221 wbkgdset(win, (chtype) (COLOR_PAIR(color) | ' ')); 222 } else if (!unboxed) { 223 wbkgdset(win, A_BOLD | ' '); 224 } 225 } 226 sprintf(userdata, "p%d", color % 8); 227 set_panel_userptr(pan, (NCURSES_CONST void *) userdata); 228 return pan; 229} 230 231static void 232my_remove_panel(PANEL ** pans, int which) 233{ 234 if (pans[which] != 0) { 235 PANEL *pan = pans[which]; 236 WINDOW *win = panel_window(pan); 237 char *user = (char *) panel_userptr(pan); 238 239 free(user); 240 del_panel(pan); 241 delwin(win); 242 243 pans[which] = 0; 244 } 245} 246 247#undef MIN 248#define MIN(a,b) ((a) < (b) ? (a) : (b)) 249#define ABS(a) ((a) < 0 ? -(a) : (a)) 250 251static void 252my_create_panel(PANEL ** pans, int which, FillPanel myFill) 253{ 254 PANEL *pan = 0; 255 int code; 256 short pair = (short) which; 257 short fg = (short) ((pair == COLOR_BLUE) ? COLOR_WHITE : COLOR_BLACK); 258 short bg = pair; 259 int x0, y0, x1, y1; 260 261 init_pair(pair, fg, bg); 262 263 /* remove the old panel, if any */ 264 my_remove_panel(pans, which); 265 266 /* get the position of one corner */ 267 wmove(stdscr, getmaxy(stdscr) / 2, getmaxx(stdscr) / 2); 268 getyx(stdscr, y0, x0); 269 while ((code = get_position("First corner", "", which, &x0, &y0)) == 0) { 270 ; 271 } 272 273 if (code > 0) { 274 char also[80]; 275 sprintf(also, " (first %d,%d)", y0, x0); 276 /* get the position of the opposite corner */ 277 while ((code = get_position("Opposite corner", 278 also, which, &x1, &y1)) == 0) { 279 ; 280 } 281 282 if (code > 0) { 283 int tly = MIN(y0, y1); 284 int tlx = MIN(x0, x1); 285 pan = mkpanel(pair, ABS(y1 - y0) + 1, ABS(x1 - x0) + 1, tly, tlx); 286 /* finish */ 287 myFill(pan); 288 pans[which] = pan; 289 pflush(); 290 wmove(stdscr, y1, x1); 291 } 292 } 293} 294 295static void 296my_move_panel(PANEL ** pans, int which, bool continuous) 297{ 298 if (pans[which] != 0) { 299 int code; 300 int y0, x0; 301 int y1, x1; 302 WINDOW *win = panel_window(pans[which]); 303 char also[80]; 304 305 getbegyx(win, y0, x0); 306 sprintf(also, " (start %d,%d)", y0, x0); 307 wmove(stdscr, y0, x0); 308 while ((code = get_position("Move panel", also, which, &x1, &y1)) == 0) { 309 if (continuous) { 310 move_panel(pans[which], y1, x1); 311 pflush(); 312 } 313 } 314 if (code > 0) { 315 move_panel(pans[which], y1, x1); 316 } 317 } 318} 319 320static void 321my_resize_panel(PANEL ** pans, int which, FillPanel myFill) 322{ 323 if (pans[which] != 0) { 324 int code; 325 int y0, x0; 326 int y1, x1; 327 WINDOW *win = panel_window(pans[which]); 328 char also[80]; 329 330 getbegyx(win, y0, x0); 331 sprintf(also, " (start %d,%d)", y0, x0); 332 wmove(stdscr, y0, x0); 333 while ((code = get_position("Resize panel", 334 also, which, &x1, &y1)) == 0) { 335 ; 336 } 337 if (code > 0) { 338 WINDOW *next = newwin(ABS(y1 - y0) + 1, 339 ABS(x1 - x0) + 1, 340 MIN(y0, y1), 341 MIN(x0, x1)); 342 if (next != 0) { 343 keypad(next, TRUE); 344 if (use_colors) { 345 wbkgdset(next, (chtype) (COLOR_PAIR(which) | ' ')); 346 } else if (!unboxed) { 347 wbkgdset(next, A_BOLD | ' '); 348 } 349 replace_panel(pans[which], next); 350 myFill(pans[which]); 351 delwin(win); 352 } 353 } 354 } 355} 356 357static void 358init_panel(void) 359{ 360 register int y, x; 361 362 for (y = 0; y < LINES - 1; y++) { 363 for (x = 0; x < COLS; x++) 364 wprintw(stdscr, "%d", (y + x) % 10); 365 } 366} 367 368static void 369fill_panel(PANEL * pan) 370{ 371 WINDOW *win = panel_window(pan); 372 const char *userptr = (const char *) panel_userptr(pan); 373 int num = (userptr && *userptr) ? userptr[1] : '?'; 374 int y, x; 375 376 wmove(win, 1, 1); 377 wprintw(win, "-pan%c-", num); 378 wclrtoeol(win); 379 box(win, 0, 0); 380 for (y = 2; y < getmaxy(win) - 1; y++) { 381 for (x = 1; x < getmaxx(win) - 1; x++) { 382 wmove(win, y, x); 383 waddch(win, UChar(num)); 384 } 385 } 386} 387 388static void 389fill_unboxed(PANEL * pan) 390{ 391 WINDOW *win = panel_window(pan); 392 const char *userptr = (const char *) panel_userptr(pan); 393 int num = (userptr && *userptr) ? userptr[1] : '?'; 394 int y, x; 395 396 for (y = 0; y < getmaxy(win); y++) { 397 for (x = 0; x < getmaxx(win); x++) { 398 wmove(win, y, x); 399 waddch(win, UChar(num)); 400 } 401 } 402} 403 404#if USE_WIDEC_SUPPORT 405static void 406make_fullwidth_digit(cchar_t *target, int digit) 407{ 408 wchar_t source[2]; 409 410 source[0] = digit + 0xff10; 411 source[1] = 0; 412 setcchar(target, source, A_NORMAL, 0, 0); 413} 414 415static void 416init_wide_panel(void) 417{ 418 int digit; 419 cchar_t temp[10]; 420 421 for (digit = 0; digit < 10; ++digit) 422 make_fullwidth_digit(&temp[digit], digit); 423 424 do { 425 int y, x; 426 getyx(stdscr, y, x); 427 digit = (y + x / 2) % 10; 428 } while (add_wch(&temp[digit]) != ERR); 429} 430 431static void 432fill_wide_panel(PANEL * pan) 433{ 434 WINDOW *win = panel_window(pan); 435 int num = ((const char *) panel_userptr(pan))[1]; 436 int y, x; 437 438 wmove(win, 1, 1); 439 wprintw(win, "-pan%c-", num); 440 wclrtoeol(win); 441 box(win, 0, 0); 442 for (y = 2; y < getmaxy(win) - 1; y++) { 443 for (x = 1; x < getmaxx(win) - 1; x++) { 444 wmove(win, y, x); 445 waddch(win, UChar(num)); 446 } 447 } 448} 449#endif 450 451#define MAX_PANELS 5 452 453static int 454which_panel(PANEL * px[MAX_PANELS + 1], PANEL * pan) 455{ 456 int result = 0; 457 int j; 458 459 for (j = 1; j <= MAX_PANELS; ++j) { 460 if (px[j] == pan) { 461 result = j; 462 break; 463 } 464 } 465 return result; 466} 467 468static void 469show_panels(PANEL * px[MAX_PANELS + 1]) 470{ 471 static const char *help[] = 472 { 473 "", 474 "Commands are letter/digit pairs. Digits are the panel number.", 475 "", 476 " b - put the panel on the bottom of the stack", 477 " c - create the panel", 478 " d - delete the panel", 479 " h - hide the panel", 480 " m - move the panel (M for continuous move)", 481 " r - resize the panel", 482 " s - show the panel", 483 " b - put the panel on the top of the stack" 484 }; 485 486 struct { 487 bool valid; 488 bool hidden; 489 PANEL *above; 490 PANEL *below; 491 } table[MAX_PANELS + 1]; 492 493 WINDOW *win; 494 PANEL *pan; 495 int j; 496 497 for (j = 1; j <= MAX_PANELS; ++j) { 498 table[j].valid = (px[j] != 0); 499 if (table[j].valid) { 500 table[j].hidden = panel_hidden(px[j]); 501 table[j].above = panel_above(px[j]); 502 table[j].below = panel_below(px[j]); 503 } 504 } 505 506 if ((win = newwin(LINES - 1, COLS, 0, 0)) != 0) { 507 keypad(win, TRUE); 508 if ((pan = new_panel(win)) != 0) { 509 werase(win); 510 mvwprintw(win, 0, 0, "Panels:\n"); 511 for (j = 1; j <= MAX_PANELS; ++j) { 512 if (table[j].valid) { 513 wprintw(win, " %d:", j); 514 if (table[j].hidden) { 515 waddstr(win, " hidden"); 516 } else { 517 if (table[j].above) { 518 wprintw(win, " above %d", 519 which_panel(px, table[j].above)); 520 } 521 if (table[j].below) { 522 wprintw(win, "%s below %d", 523 table[j].above ? "," : "", 524 which_panel(px, table[j].below)); 525 } 526 } 527 waddch(win, '\n'); 528 } 529 } 530 for (j = 0; j < (int) SIZEOF(help); ++j) { 531 if (wprintw(win, "%s\n", help[j]) == ERR) 532 break; 533 } 534 wgetch(win); 535 del_panel(pan); 536 pflush(); 537 } 538 delwin(win); 539 } 540} 541 542#define wrapper(func) \ 543static int my_##func(PANEL *pan) \ 544{ \ 545 int code = ERR; \ 546 if (pan != 0) { \ 547 code = func(pan); \ 548 } \ 549 return code; \ 550} 551/* *INDENT-OFF* */ 552wrapper(bottom_panel) 553wrapper(hide_panel) 554wrapper(show_panel) 555wrapper(top_panel) 556/* *INDENT-ON* */ 557 558static void 559do_panel(PANEL * px[MAX_PANELS + 1], 560 NCURSES_CONST char *cmd, 561 FillPanel myFill) 562{ 563 int which = cmd[1] - '0'; 564 565 if (which < 1 || which > MAX_PANELS) { 566 beep(); 567 return; 568 } 569 570 if (log_in != 0) { 571 pflush(); 572 } 573 574 saywhat(cmd); 575 switch (*cmd) { 576 case 'b': 577 my_bottom_panel(px[which]); 578 break; 579 case 'c': 580 my_create_panel(px, which, myFill); 581 break; 582 case 'd': 583 my_remove_panel(px, which); 584 break; 585 case 'h': 586 my_hide_panel(px[which]); 587 break; 588 case 'm': 589 my_move_panel(px, which, FALSE); 590 break; 591 case 'M': 592 my_move_panel(px, which, TRUE); 593 break; 594 case 'r': 595 my_resize_panel(px, which, myFill); 596 break; 597 case 's': 598 my_show_panel(px[which]); 599 break; 600 case 't': 601 my_top_panel(px[which]); 602 break; 603 } 604} 605 606static bool 607ok_letter(int ch) 608{ 609 return isalpha(UChar(ch)) && strchr("bcdhmMrst", ch) != 0; 610} 611 612static bool 613ok_digit(int ch) 614{ 615 return isdigit(UChar(ch)) && (ch >= '1') && (ch - '0' <= MAX_PANELS); 616} 617 618/* 619 * A command consists of one or more letter/digit pairs separated by a space. 620 * Digits are limited to 1..MAX_PANELS. 621 * 622 * End the command with a newline. Reject other characters. 623 */ 624static bool 625get_command(PANEL * px[MAX_PANELS + 1], char *buffer, int limit) 626{ 627 int length = 0; 628 int y0, x0; 629 int c0, ch; 630 WINDOW *win; 631 632 getyx(stdscr, y0, x0); 633 win = statusline(); 634 waddstr(win, "Command:"); 635 buffer[length = 0] = '\0'; 636 637 if (log_in != 0) { 638 if (fgets(buffer, limit - 3, log_in) != 0) { 639 length = (int) strlen(buffer); 640 while (length > 0 && isspace(UChar(buffer[length - 1]))) 641 buffer[--length] = '\0'; 642 waddstr(win, buffer); 643 } else { 644 close_input(); 645 } 646 (void) wgetch(win); 647 } else { 648 c0 = 0; 649 for (;;) { 650 ch = wgetch(win); 651 if (ch == ERR || ch == QUIT || ch == ESCAPE) { 652 buffer[0] = '\0'; 653 break; 654 } else if (ch == CTRL('L')) { 655 wrefresh(curscr); 656 } else if (ch == '\n' || ch == KEY_ENTER) { 657 break; 658 } else if (ch == '?') { 659 show_panels(px); 660 } else if (length + 3 < limit) { 661 if (ch >= KEY_MIN) { 662 beep(); 663 } else if (ok_letter(UChar(ch))) { 664 if (isalpha(UChar(c0))) { 665 beep(); 666 } else if (isdigit(UChar(c0))) { 667 wprintw(win, " %c", ch); 668 buffer[length++] = ' '; 669 buffer[length++] = (char) (c0 = ch); 670 } else { 671 wprintw(win, "%c", ch); 672 buffer[length++] = (char) (c0 = ch); 673 } 674 } else if (ok_digit(ch)) { 675 if (isalpha(UChar(c0))) { 676 wprintw(win, "%c", ch); 677 buffer[length++] = (char) (c0 = ch); 678 } else { 679 beep(); 680 } 681 } else if (ch == ' ') { 682 if (isdigit(UChar(c0))) { 683 wprintw(win, "%c", ch); 684 buffer[length++] = (char) (c0 = ch); 685 } else { 686 beep(); 687 } 688 } else { 689 beep(); 690 } 691 } else { 692 beep(); 693 } 694 } 695 } 696 697 wmove(stdscr, y0, x0); 698 699 buffer[length] = '\0'; 700 if (log_out && length) { 701 fprintf(log_out, "%s\n", buffer); 702 } 703 return (length != 0); 704} 705 706static void 707demo_panels(InitPanel myInit, FillPanel myFill) 708{ 709 int itmp; 710 PANEL *px[MAX_PANELS + 1]; 711 char buffer[BUFSIZ]; 712 713 scrollok(stdscr, FALSE); /* we don't want stdscr to scroll! */ 714 refresh(); 715 716 myInit(); 717 memset(px, 0, sizeof(px)); 718 719 while (get_command(px, buffer, sizeof(buffer))) { 720 int limit = (int) strlen(buffer); 721 for (itmp = 0; itmp < limit; itmp += 3) { 722 do_panel(px, buffer + itmp, myFill); 723 } 724 pflush(); 725 } 726#if NO_LEAKS 727 for (itmp = 1; itmp <= MAX_PANELS; ++itmp) { 728 my_remove_panel(px, itmp); 729 } 730#endif 731} 732 733static void 734usage(void) 735{ 736 static const char *const tbl[] = 737 { 738 "Usage: demo_panels [options]" 739 ,"" 740 ,"Options:" 741 ," -i file read commands from file" 742 ," -o file record commands in file" 743 ," -m do not use colors" 744#if USE_WIDEC_SUPPORT 745 ," -w use wide-characters in panels and background" 746#endif 747 ," -x do not enclose panels in boxes" 748 }; 749 size_t n; 750 for (n = 0; n < SIZEOF(tbl); n++) 751 fprintf(stderr, "%s\n", tbl[n]); 752 ExitProgram(EXIT_FAILURE); 753} 754 755int 756main(int argc, char *argv[]) 757{ 758 int c; 759 bool monochrome = FALSE; 760 InitPanel myInit = init_panel; 761 FillPanel myFill = fill_panel; 762 763 setlocale(LC_ALL, ""); 764 765 while ((c = getopt(argc, argv, "i:o:mwx")) != -1) { 766 switch (c) { 767 case 'i': 768 log_in = fopen(optarg, "r"); 769 break; 770 case 'o': 771 log_out = fopen(optarg, "w"); 772 break; 773 case 'm': 774 monochrome = TRUE; 775 break; 776#if USE_WIDEC_SUPPORT 777 case 'w': 778 myInit = init_wide_panel; 779 myFill = fill_wide_panel; 780 break; 781#endif 782 case 'x': 783 unboxed = TRUE; 784 break; 785 default: 786 usage(); 787 } 788 } 789 if (unboxed) 790 myFill = fill_unboxed; 791 792 initscr(); 793 cbreak(); 794 noecho(); 795 keypad(stdscr, TRUE); 796 797 use_colors = monochrome ? FALSE : has_colors(); 798 if (use_colors) 799 start_color(); 800 801 demo_panels(myInit, myFill); 802 endwin(); 803 804 close_input(); 805 close_output(); 806 807 ExitProgram(EXIT_SUCCESS); 808} 809#else 810int 811main(void) 812{ 813 printf("This program requires the curses panel library\n"); 814 ExitProgram(EXIT_FAILURE); 815} 816#endif 817