1<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" 2"http://www.w3.org/TR/html4/strict.dtd"> 3<html> 4<head> 5 <meta name="generator" content= 6 "HTML Tidy for HTML5 for Linux version 5.6.0"> 7 <title>NCURSES Programming HOWTO</title> 8 <meta name="GENERATOR" content= 9 "Modular DocBook HTML Stylesheet Version 1.79"> 10</head> 11<body class="ARTICLE" bgcolor="#FFFFFF" text="#000000" link= 12"#0000FF" vlink="#840084" alink="#0000FF"> 13 <div class="ARTICLE"> 14 <div class="TITLEPAGE"> 15 <h1 class="TITLE"><a name="AEN2" id="AEN2">NCURSES 16 Programming HOWTO</a></h1> 17 18 <h3 class="AUTHOR"><a name="AEN4" id="AEN4">Pradeep 19 Padala</a></h3> 20 21 <div class="AFFILIATION"> 22 <div class="ADDRESS"> 23 <p class="ADDRESS"><code class="EMAIL"><<a href= 24 "mailto:ppadala@gmail.com">ppadala@gmail.com</a>></code> 25 </p> 26 </div> 27 </div> 28 29 <p class="PUBDATE">v1.9, 2005-06-20<br></p> 30 31 <div class="REVHISTORY"> 32 <table width="100%" border="0" summary="revisions"> 33 <tr> 34 <th align="left" valign="top" colspan="3"><b>Revision 35 History</b> 36 </th> 37 </tr> 38 39 <tr> 40 <td align="left">Revision 2.0</td> 41 <td align="left">2022-12-03</td> 42 <td align="left">Revised by: dickey</td> 43 </tr> 44 45 <tr> 46 <td align="left" colspan="3">Fixes for the sample 47 programs, Correct documentation errata.</td> 48 </tr> 49 50 <tr> 51 <td align="left">Revision 1.9</td> 52 <td align="left">2005-06-20</td> 53 <td align="left">Revised by: ppadala</td> 54 </tr> 55 56 <tr> 57 <td align="left" colspan="3">The license has been 58 changed to the MIT-style license used by NCURSES. Note 59 that the programs are also re-licensed under this.</td> 60 </tr> 61 62 <tr> 63 <td align="left">Revision 1.8</td> 64 <td align="left">2005-06-17</td> 65 <td align="left">Revised by: ppadala</td> 66 </tr> 67 68 <tr> 69 <td align="left" colspan="3">Lots of updates. Added 70 references and perl examples. Changes to examples. Many 71 grammatical and stylistic changes to the content. 72 Changes to NCURSES history.</td> 73 </tr> 74 75 <tr> 76 <td align="left">Revision 1.7.1</td> 77 <td align="left">2002-06-25</td> 78 <td align="left">Revised by: ppadala</td> 79 </tr> 80 81 <tr> 82 <td align="left" colspan="3">Added a README file for 83 building and instructions for building from 84 source.</td> 85 </tr> 86 87 <tr> 88 <td align="left">Revision 1.7</td> 89 <td align="left">2002-06-25</td> 90 <td align="left">Revised by: ppadala</td> 91 </tr> 92 93 <tr> 94 <td align="left" colspan="3">Added "Other formats" 95 section and made a lot of fancy changes to the 96 programs. Inlining of programs is gone.</td> 97 </tr> 98 99 <tr> 100 <td align="left">Revision 1.6.1</td> 101 <td align="left">2002-02-24</td> 102 <td align="left">Revised by: ppadala</td> 103 </tr> 104 105 <tr> 106 <td align="left" colspan="3">Removed the old Changelog 107 section, cleaned the makefiles</td> 108 </tr> 109 110 <tr> 111 <td align="left">Revision 1.6</td> 112 <td align="left">2002-02-16</td> 113 <td align="left">Revised by: ppadala</td> 114 </tr> 115 116 <tr> 117 <td align="left" colspan="3">Corrected a lot of 118 spelling mistakes, added ACS variables section</td> 119 </tr> 120 121 <tr> 122 <td align="left">Revision 1.5</td> 123 <td align="left">2002-01-05</td> 124 <td align="left">Revised by: ppadala</td> 125 </tr> 126 127 <tr> 128 <td align="left" colspan="3">Changed structure to 129 present proper TOC</td> 130 </tr> 131 132 <tr> 133 <td align="left">Revision 1.3.1</td> 134 <td align="left">2001-07-26</td> 135 <td align="left">Revised by: ppadala</td> 136 </tr> 137 138 <tr> 139 <td align="left" colspan="3">Corrected maintainers 140 paragraph, Corrected stable release number</td> 141 </tr> 142 143 <tr> 144 <td align="left">Revision 1.3</td> 145 <td align="left">2001-07-24</td> 146 <td align="left">Revised by: ppadala</td> 147 </tr> 148 149 <tr> 150 <td align="left" colspan="3">Added copyright notices to 151 main document (LDP license) and programs (GPL), 152 Corrected printw_example.</td> 153 </tr> 154 155 <tr> 156 <td align="left">Revision 1.2</td> 157 <td align="left">2001-06-05</td> 158 <td align="left">Revised by: ppadala</td> 159 </tr> 160 161 <tr> 162 <td align="left" colspan="3">Incorporated ravi's 163 changes. Mainly to introduction, menu, form, justforfun 164 sections</td> 165 </tr> 166 167 <tr> 168 <td align="left">Revision 1.1</td> 169 <td align="left">2001-05-22</td> 170 <td align="left">Revised by: ppadala</td> 171 </tr> 172 173 <tr> 174 <td align="left" colspan="3">Added "a word about 175 window" section, Added scanw_example.</td> 176 </tr> 177 </table> 178 </div> 179 180 <div> 181 <div class="ABSTRACT"> 182 <a name="AEN72" id="AEN72"></a> 183 <p><span class="emphasis"><i class="EMPHASIS">This 184 document is intended to be an "All in One" guide for 185 programming with ncurses and its sister libraries. We 186 graduate from a simple "Hello World" program to more 187 complex form manipulation. No prior experience in ncurses 188 is assumed. Send comments to <a href= 189 "mailto:ppadala@gmail.com" target="_top">this 190 address</a></i></span> 191 </p> 192 </div> 193 </div> 194 195 <hr> 196 </div> 197 198 <div class="TOC"> 199 <dl> 200 <dt><b>Table of Contents</b> 201 </dt> 202 203 <dt>1. <a href="#INTRO">Introduction</a></dt> 204 205 <dd> 206 <dl> 207 <dt>1.1. <a href="#WHATIS">What is NCURSES?</a></dt> 208 209 <dt>1.2. <a href="#WHATCANWEDO">What we can do with 210 NCURSES</a></dt> 211 212 <dt>1.3. <a href="#WHERETOGETIT">Where to get 213 it</a></dt> 214 215 <dt>1.4. <a href="#PURPOSE">Purpose/Scope of the 216 document</a></dt> 217 218 <dt>1.5. <a href="#ABOUTPROGRAMS">About the 219 Programs</a></dt> 220 221 <dt>1.6. <a href="#OTHERFORMATS">Other Formats of the 222 document</a></dt> 223 224 <dd> 225 <dl> 226 <dt>1.6.1. <a href="#LISTFORMATS">Readily available 227 formats from tldp.org</a></dt> 228 229 <dt>1.6.2. <a href="#BUILDSOURCE">Building from 230 source</a></dt> 231 </dl> 232 </dd> 233 234 <dt>1.7. <a href="#CREDITS">Credits</a></dt> 235 236 <dt>1.8. <a href="#WISHLIST">Wish List</a></dt> 237 238 <dt>1.9. <a href="#COPYRIGHT">Copyright</a></dt> 239 </dl> 240 </dd> 241 242 <dt>2. <a href="#HELLOWORLD">Hello World !!!</a></dt> 243 244 <dd> 245 <dl> 246 <dt>2.1. <a href="#COMPILECURSES">Compiling With the 247 NCURSES Library</a></dt> 248 249 <dt>2.2. <a href="#DISSECTION">Dissection</a></dt> 250 251 <dd> 252 <dl> 253 <dt>2.2.1. <a href="#ABOUT-INITSCR">About 254 initscr()</a></dt> 255 256 <dt>2.2.2. <a href="#MYST-REFRESH">The mysterious 257 refresh()</a></dt> 258 259 <dt>2.2.3. <a href="#ABOUT-ENDWIN">About 260 endwin()</a></dt> 261 </dl> 262 </dd> 263 </dl> 264 </dd> 265 266 <dt>3. <a href="#GORY">The Gory Details</a></dt> 267 268 <dt>4. <a href="#INIT">Initialization</a></dt> 269 270 <dd> 271 <dl> 272 <dt>4.1. <a href="#ABOUTINIT">Initialization 273 functions</a></dt> 274 275 <dt>4.2. <a href="#RAWCBREAK">raw() and 276 cbreak()</a></dt> 277 278 <dt>4.3. <a href="#ECHONOECHO">echo() and 279 noecho()</a></dt> 280 281 <dt>4.4. <a href="#KEYPAD">keypad()</a></dt> 282 283 <dt>4.5. <a href="#HALFDELAY">halfdelay()</a></dt> 284 285 <dt>4.6. <a href="#MISCINIT">Miscellaneous 286 Initialization functions</a></dt> 287 288 <dt>4.7. <a href="#INITEX">An Example</a></dt> 289 </dl> 290 </dd> 291 292 <dt>5. <a href="#AWORDWINDOWS">A Word about 293 Windows</a></dt> 294 295 <dt>6. <a href="#PRINTW">Output functions</a></dt> 296 297 <dd> 298 <dl> 299 <dt>6.1. <a href="#ADDCHCLASS">addch() class of 300 functions</a></dt> 301 302 <dt>6.2. <a href="#AEN303">mvaddch(), waddch() and 303 mvwaddch()</a></dt> 304 305 <dt>6.3. <a href="#PRINTWCLASS">printw() class of 306 functions</a></dt> 307 308 <dd> 309 <dl> 310 <dt>6.3.1. <a href="#PRINTWMVPRINTW">printw() and 311 mvprintw</a></dt> 312 313 <dt>6.3.2. <a href="#WPRINTWMVWPRINTW">wprintw() 314 and mvwprintw</a></dt> 315 316 <dt>6.3.3. <a href="#VWPRINTW">vw_printw()</a></dt> 317 318 <dt>6.3.4. <a href="#SIMPLEPRINTWEX">A Simple 319 printw example</a></dt> 320 </dl> 321 </dd> 322 323 <dt>6.4. <a href="#ADDSTRCLASS">addstr() class of 324 functions</a></dt> 325 326 <dt>6.5. <a href="#ACAUTION">A word of caution</a></dt> 327 </dl> 328 </dd> 329 330 <dt>7. <a href="#SCANW">Input functions</a></dt> 331 332 <dd> 333 <dl> 334 <dt>7.1. <a href="#GETCHCLASS">getch() class of 335 functions</a></dt> 336 337 <dt>7.2. <a href="#SCANWCLASS">scanw() class of 338 functions</a></dt> 339 340 <dd> 341 <dl> 342 <dt>7.2.1. <a href="#SCANWMVSCANW">scanw() and 343 mvscanw</a></dt> 344 345 <dt>7.2.2. <a href="#WSCANWMVWSCANW">wscanw() and 346 mvwscanw()</a></dt> 347 348 <dt>7.2.3. <a href="#VWSCANW">vw_scanw()</a></dt> 349 </dl> 350 </dd> 351 352 <dt>7.3. <a href="#GETSTRCLASS">getstr() class of 353 functions</a></dt> 354 355 <dt>7.4. <a href="#GETSTREX">Some examples</a></dt> 356 </dl> 357 </dd> 358 359 <dt>8. <a href="#ATTRIB">Attributes</a></dt> 360 361 <dd> 362 <dl> 363 <dt>8.1. <a href="#ATTRIBDETAILS">The details</a></dt> 364 365 <dt>8.2. <a href="#ATTRONVSATTRSET">attron() vs 366 attrset()</a></dt> 367 368 <dt>8.3. <a href="#ATTRGET">attr_get()</a></dt> 369 370 <dt>8.4. <a href="#ATTRFUNCS">attr_ functions</a></dt> 371 372 <dt>8.5. <a href="#WATTRFUNCS">wattr functions</a></dt> 373 374 <dt>8.6. <a href="#CHGAT">chgat() functions</a></dt> 375 </dl> 376 </dd> 377 378 <dt>9. <a href="#WINDOWS">Windows</a></dt> 379 380 <dd> 381 <dl> 382 <dt>9.1. <a href="#WINDOWBASICS">The basics</a></dt> 383 384 <dt>9.2. <a href="#LETBEWINDOW">Let there be a Window 385 !!!</a></dt> 386 387 <dt>9.3. <a href="#BORDEREXEXPL">Explanation</a></dt> 388 389 <dt>9.4. <a href="#OTHERSTUFF">The other stuff in the 390 example</a></dt> 391 392 <dt>9.5. <a href="#OTHERBORDERFUNCS">Other Border 393 functions</a></dt> 394 </dl> 395 </dd> 396 397 <dt>10. <a href="#COLOR">Colors</a></dt> 398 399 <dd> 400 <dl> 401 <dt>10.1. <a href="#COLORBASICS">The basics</a></dt> 402 403 <dt>10.2. <a href="#CHANGECOLORDEFS">Changing Color 404 Definitions</a></dt> 405 406 <dt>10.3. <a href="#COLORCONTENT">Color 407 Content</a></dt> 408 </dl> 409 </dd> 410 411 <dt>11. <a href="#KEYS">Interfacing with the key 412 board</a></dt> 413 414 <dd> 415 <dl> 416 <dt>11.1. <a href="#KEYSBASICS">The Basics</a></dt> 417 418 <dt>11.2. <a href="#SIMPLEKEYEX">A Simple Key Usage 419 example</a></dt> 420 </dl> 421 </dd> 422 423 <dt>12. <a href="#MOUSE">Interfacing with the 424 mouse</a></dt> 425 426 <dd> 427 <dl> 428 <dt>12.1. <a href="#MOUSEBASICS">The Basics</a></dt> 429 430 <dt>12.2. <a href="#GETTINGEVENTS">Getting the 431 events</a></dt> 432 433 <dt>12.3. <a href="#MOUSETOGETHER">Putting it all 434 Together</a></dt> 435 436 <dt>12.4. <a href="#MISCMOUSEFUNCS">Miscellaneous 437 Functions</a></dt> 438 </dl> 439 </dd> 440 441 <dt>13. <a href="#SCREEN">Screen Manipulation</a></dt> 442 443 <dd> 444 <dl> 445 <dt>13.1. <a href="#GETYX">getyx() functions</a></dt> 446 447 <dt>13.2. <a href="#SCREENDUMP">Screen Dumping</a></dt> 448 449 <dt>13.3. <a href="#WINDOWDUMP">Window Dumping</a></dt> 450 </dl> 451 </dd> 452 453 <dt>14. <a href="#MISC">Miscellaneous features</a></dt> 454 455 <dd> 456 <dl> 457 <dt>14.1. <a href="#CURSSET">curs_set()</a></dt> 458 459 <dt>14.2. <a href="#TEMPLEAVE">Temporarily Leaving 460 Curses mode</a></dt> 461 462 <dt>14.3. <a href="#ACSVARS">ACS_ variables</a></dt> 463 </dl> 464 </dd> 465 466 <dt>15. <a href="#OTHERLIB">Other libraries</a></dt> 467 468 <dt>16. <a href="#PANELS">Panel Library</a></dt> 469 470 <dd> 471 <dl> 472 <dt>16.1. <a href="#PANELBASICS">The Basics</a></dt> 473 474 <dt>16.2. <a href="#COMPILEPANELS">Compiling With the 475 Panels Library</a></dt> 476 477 <dt>16.3. <a href="#PANELBROWSING">Panel Window 478 Browsing</a></dt> 479 480 <dt>16.4. <a href="#USERPTRUSING">Using User 481 Pointers</a></dt> 482 483 <dt>16.5. <a href="#PANELMOVERESIZE">Moving and 484 Resizing Panels</a></dt> 485 486 <dt>16.6. <a href="#PANELSHOWHIDE">Hiding and Showing 487 Panels</a></dt> 488 489 <dt>16.7. <a href="#PANELABOVE">panel_above() and 490 panel_below() Functions</a></dt> 491 </dl> 492 </dd> 493 494 <dt>17. <a href="#MENUS">Menus Library</a></dt> 495 496 <dd> 497 <dl> 498 <dt>17.1. <a href="#MENUBASICS">The Basics</a></dt> 499 500 <dt>17.2. <a href="#COMPILEMENUS">Compiling With the 501 Menu Library</a></dt> 502 503 <dt>17.3. <a href="#MENUDRIVER">Menu Driver: The work 504 horse of the menu system</a></dt> 505 506 <dt>17.4. <a href="#MENUWINDOWS">Menu Windows</a></dt> 507 508 <dt>17.5. <a href="#SCROLLMENUS">Scrolling 509 Menus</a></dt> 510 511 <dt>17.6. <a href="#MULTICOLUMN">Multi Columnar 512 Menus</a></dt> 513 514 <dt>17.7. <a href="#MULTIVALUEMENUS">Multi Valued 515 Menus</a></dt> 516 517 <dt>17.8. <a href="#MENUOPT">Menu Options</a></dt> 518 519 <dt>17.9. <a href="#MENUUSERPTR">The useful User 520 Pointer</a></dt> 521 </dl> 522 </dd> 523 524 <dt>18. <a href="#FORMS">Forms Library</a></dt> 525 526 <dd> 527 <dl> 528 <dt>18.1. <a href="#FORMBASICS">The Basics</a></dt> 529 530 <dt>18.2. <a href="#COMPILEFORMS">Compiling With the 531 Forms Library</a></dt> 532 533 <dt>18.3. <a href="#PLAYFIELDS">Playing with 534 Fields</a></dt> 535 536 <dd> 537 <dl> 538 <dt>18.3.1. <a href="#FETCHINFO">Fetching Size and 539 Location of Field</a></dt> 540 541 <dt>18.3.2. <a href="#MOVEFIELD">Moving the 542 field</a></dt> 543 544 <dt>18.3.3. <a href="#JUSTIFYFIELD">Field 545 Justification</a></dt> 546 547 <dt>18.3.4. <a href="#FIELDDISPATTRIB">Field 548 Display Attributes</a></dt> 549 550 <dt>18.3.5. <a href="#FIELDOPTIONBITS">Field Option 551 Bits</a></dt> 552 553 <dt>18.3.6. <a href="#FIELDSTATUS">Field 554 Status</a></dt> 555 556 <dt>18.3.7. <a href="#FIELDUSERPTR">Field User 557 Pointer</a></dt> 558 559 <dt>18.3.8. <a href= 560 "#VARIABLESIZEFIELDS">Variable-Sized 561 Fields</a></dt> 562 </dl> 563 </dd> 564 565 <dt>18.4. <a href="#FORMWINDOWS">Form Windows</a></dt> 566 567 <dt>18.5. <a href="#FILEDVALIDATE">Field 568 Validation</a></dt> 569 570 <dt>18.6. <a href="#FORMDRIVER">Form Driver: The work 571 horse of the forms system</a></dt> 572 573 <dd> 574 <dl> 575 <dt>18.6.1. <a href="#PAGENAVREQ">Page Navigation 576 Requests</a></dt> 577 578 <dt>18.6.2. <a href="#INTERFIELDNAVREQ">Inter-Field 579 Navigation Requests</a></dt> 580 581 <dt>18.6.3. <a href="#INTRAFIELDNAVREQ">Intra-Field 582 Navigation Requests</a></dt> 583 584 <dt>18.6.4. <a href="#SCROLLREQ">Scrolling 585 Requests</a></dt> 586 587 <dt>18.6.5. <a href="#EDITREQ">Editing 588 Requests</a></dt> 589 590 <dt>18.6.6. <a href="#ORDERREQ">Order 591 Requests</a></dt> 592 593 <dt>18.6.7. <a href="#APPLICCOMMANDS">Application 594 Commands</a></dt> 595 </dl> 596 </dd> 597 </dl> 598 </dd> 599 600 <dt>19. <a href="#TOOLS">Tools and Widget 601 Libraries</a></dt> 602 603 <dd> 604 <dl> 605 <dt>19.1. <a href="#CDK">CDK (Curses Development 606 Kit)</a></dt> 607 608 <dd> 609 <dl> 610 <dt>19.1.1. <a href="#WIDGETLIST">Widget 611 List</a></dt> 612 613 <dt>19.1.2. <a href="#CDKATTRACT">Some Attractive 614 Features</a></dt> 615 616 <dt>19.1.3. <a href= 617 "#CDKCONCLUSION">Conclusion</a></dt> 618 </dl> 619 </dd> 620 621 <dt>19.2. <a href="#DIALOG">The dialog</a></dt> 622 623 <dt>19.3. <a href="#PERLCURSES">Perl Curses Modules 624 CURSES::FORM and CURSES::WIDGETS</a></dt> 625 </dl> 626 </dd> 627 628 <dt>20. <a href="#JUSTFORFUN">Just For Fun !!!</a></dt> 629 630 <dd> 631 <dl> 632 <dt>20.1. <a href="#GAMEOFLIFE">The Game of 633 Life</a></dt> 634 635 <dt>20.2. <a href="#MAGIC">Magic Square</a></dt> 636 637 <dt>20.3. <a href="#HANOI">Towers of Hanoi</a></dt> 638 639 <dt>20.4. <a href="#QUEENS">Queens Puzzle</a></dt> 640 641 <dt>20.5. <a href="#SHUFFLE">Shuffle</a></dt> 642 643 <dt>20.6. <a href="#TT">Typing Tutor</a></dt> 644 </dl> 645 </dd> 646 647 <dt>21. <a href="#REF">References</a></dt> 648 </dl> 649 </div> 650 651 <div class="SECT1"> 652 <h2 class="SECT1"><a name="INTRO" id="INTRO">1. 653 Introduction</a></h2> 654 655 <p>In the olden days of teletype terminals, terminals were 656 away from computers and were connected to them through serial 657 cables. The terminals could be configured by sending a series 658 of bytes. All the capabilities (such as moving the cursor to 659 a new location, erasing part of the screen, scrolling the 660 screen, changing modes, etc.) of terminals could be accessed 661 through these series of bytes. These control seeuqnces are 662 usually called escape sequences, because they start with an 663 escape(0x1B) character. Even today, with proper emulation, we 664 can send escape sequences to the emulator and achieve the 665 same effect on a terminal window.</p> 666 667 <p>Suppose you wanted to print a line in color. Try typing 668 this on your console.</p> 669 670 <pre class="PROGRAMLISTING">echo "^[[0;31;40mIn Color"</pre> 671 <p>The first character is an escape character, which looks 672 like two characters ^ and [. To be able to print it, you have 673 to press CTRL+V and then the ESC key. All the others are 674 normal printable characters. You should be able to see the 675 string "In Color" in red. It stays that way and to revert 676 back to the original mode type this.</p> 677 678 <pre class="PROGRAMLISTING">echo "^[[0;37;40m"</pre> 679 <p>Now, what do these magic characters mean? Difficult to 680 comprehend? They might even be different for different 681 terminals. So the designers of UNIX invented a mechanism 682 named <tt class="LITERAL">termcap</tt>. It is a file that 683 lists all the capabilities of a particular terminal, along 684 with the escape sequences needed to achieve a particular 685 effect. In the later years, this was replaced by <tt class= 686 "LITERAL">terminfo</tt>. Without delving too much into 687 details, this mechanism allows application programs to query 688 the terminfo database and obtain the control characters to be 689 sent to a terminal or terminal emulator.</p> 690 691 <div class="SECT2"> 692 <hr> 693 694 <h3 class="SECT2"><a name="WHATIS" id="WHATIS">1.1. What is 695 NCURSES?</a></h3> 696 697 <p>You might be wondering, what the import of all this 698 technical gibberish is. In the above scenario, every 699 application program is supposed to query the terminfo and 700 perform the necessary stuff (sending control characters, 701 etc.). It soon became difficult to manage this complexity 702 and this gave birth to 'CURSES'. Curses is a pun on the 703 name "cursor optimization". The Curses library forms a 704 wrapper over working with raw terminal codes, and provides 705 highly flexible and efficient API (Application Programming 706 Interface). It provides functions to move the cursor, 707 create windows, produce colors, play with mouse, etc. The 708 application programs need not worry about the underlying 709 terminal capabilities.</p> 710 711 <p>So what is NCURSES? NCURSES is a clone of the original 712 System V Release 4.0 (SVr4) curses. It is a freely 713 distributable library, fully compatible with older version 714 of curses. In short, it is a library of functions that 715 manages an application's display on character-cell 716 terminals. In the remainder of the document, the terms 717 curses and ncurses are used interchangeably.</p> 718 719 <p>A detailed history of NCURSES can be found in the NEWS 720 file from the source distribution. The current package is 721 maintained by <a href="mailto:dickey@invisible-island.net" 722 target="_top">Thomas Dickey</a>. You can contact the 723 maintainers at <a href="mailto:bug-ncurses@gnu.org" target= 724 "_top">bug-ncurses@gnu.org</a>.</p> 725 </div> 726 727 <div class="SECT2"> 728 <hr> 729 730 <h3 class="SECT2"><a name="WHATCANWEDO" id= 731 "WHATCANWEDO">1.2. What we can do with NCURSES</a></h3> 732 733 <p>NCURSES not only creates a wrapper over terminal 734 capabilities, but also gives a robust framework to create 735 nice looking UI (User Interface)s in text mode. It provides 736 functions to create windows, etc. Its sister libraries 737 panel, menu and form provide an extension to the basic 738 curses library. These libraries usually come along with 739 curses. One can create applications that contain multiple 740 windows, menus, panels and forms. Windows can be managed 741 independently, can provide 'scrollability' and even can be 742 hidden.</p> 743 744 <p>Menus provide the user with an easy command selection 745 option. Forms allow the creation of easy-to-use data entry 746 and display windows. Panels extend the capabilities of 747 ncurses to deal with overlapping and stacked windows.</p> 748 749 <p>These are just some of the basic things we can do with 750 ncurses. As we move along, We will see all the capabilities 751 of these libraries.</p> 752 </div> 753 754 <div class="SECT2"> 755 <hr> 756 757 <h3 class="SECT2"><a name="WHERETOGETIT" id= 758 "WHERETOGETIT">1.3. Where to get it</a></h3> 759 760 <p>All right, now that you know what you can do with 761 ncurses, you must be rearing to get started. NCURSES is 762 usually shipped with your installation. In case you don't 763 have the library or want to compile it on your own, read 764 on.</p> 765 766 <p><span class="emphasis"><i class="EMPHASIS">Compiling the 767 package</i></span> 768 </p> 769 770 <p>NCURSES can be obtained from <a href= 771 "ftp://ftp.gnu.org/pub/gnu/ncurses/ncurses.tar.gz" target= 772 "_top">ftp://ftp.gnu.org/pub/gnu/ncurses/ncurses.tar.gz</a> 773 or any of the ftp sites mentioned in <a href= 774 "https://www.gnu.org/order/ftp.html" target= 775 "_top">https://www.gnu.org/order/ftp.html</a>.</p> 776 777 <p>Read the README and INSTALL files for details on to how 778 to install it. It usually involves the following 779 operations.</p> 780 781 <pre class= 782 "PROGRAMLISTING"> tar zxvf ncurses<version>.tar.gz # unzip and untar the archive 783 cd ncurses<version> # cd to the directory 784 ./configure # configure the build according to your 785 # environment 786 make # make it 787 su root # become root 788 make install # install it</pre> 789 <p><span class="emphasis"><i class="EMPHASIS">Using the 790 RPM</i></span> 791 </p> 792 793 <p>NCURSES RPM can be found and downloaded from <a href= 794 "https://rpmfind.net" target="_top">https://rpmfind.net</a> 795 . The RPM can be installed with the following command after 796 becoming root.</p> 797 798 <pre class= 799 "PROGRAMLISTING"> rpm -i <downloaded rpm></pre> 800 </div> 801 802 <div class="SECT2"> 803 <hr> 804 805 <h3 class="SECT2"><a name="PURPOSE" id="PURPOSE">1.4. 806 Purpose/Scope of the document</a></h3> 807 808 <p>This document is intended to be a "All in One" guide for 809 programming with ncurses and its sister libraries. We 810 graduate from a simple "Hello World" program to more 811 complex form manipulation. No prior experience in ncurses 812 is assumed. The writing is informal, but a lot of detail is 813 provided for each of the examples.</p> 814 </div> 815 816 <div class="SECT2"> 817 <hr> 818 819 <h3 class="SECT2"><a name="ABOUTPROGRAMS" id= 820 "ABOUTPROGRAMS">1.5. About the Programs</a></h3> 821 822 <p>All the programs in the document are available in zipped 823 form <a href= 824 "https://www.tldp.org/HOWTO/NCURSES-Programming-HOWTO/ncurses_programs.tar.gz" 825 target="_top">here</a>. Unzip and untar it. The directory 826 structure looks like this.</p> 827 828 <pre class="PROGRAMLISTING">ncurses 829 | 830 |----> JustForFun -- just for fun programs 831 |----> basics -- basic programs 832 |----> demo -- output files go into this directory after make 833 | | 834 | |----> exe -- exe files of all example programs 835 |----> forms -- programs related to form library 836 |----> menus -- programs related to menus library 837 |----> panels -- programs related to panels library 838 |----> perl -- perl equivalents of the examples (contributed 839 | by Anuradha Ratnaweera) 840 |----> Makefile -- the top level Makefile 841 |----> README -- the top level README file. contains instructions 842 |----> COPYING -- copyright notice</pre> 843 <p>The individual directories contain the following 844 files.</p> 845 846 <pre class= 847 "PROGRAMLISTING">Description of files in each directory 848-------------------------------------- 849JustForFun 850 | 851 |----> hanoi.c -- The Towers of Hanoi Solver 852 |----> life.c -- The Game of Life demo 853 |----> magic.c -- An Odd Order Magic Square builder 854 |----> queens.c -- The famous N-Queens Solver 855 |----> shuffle.c -- A fun game, if you have time to kill 856 |----> tt.c -- A very trivial typing tutor 857 858 basics 859 | 860 |----> acs_vars.c -- ACS_ variables example 861 |----> hello_world.c -- Simple "Hello World" Program 862 |----> init_func_example.c -- Initialization functions example 863 |----> key_code.c -- Shows the scan code of the key pressed 864 |----> mouse_menu.c -- A menu accessible by mouse 865 |----> other_border.c -- Shows usage of other border functions apa 866 | -- rt from box() 867 |----> printw_example.c -- A very simple printw() example 868 |----> scanw_example.c -- A very simple getstr() example 869 |----> simple_attr.c -- A program that can print a c file with 870 | -- comments in attribute 871 |----> simple_color.c -- A simple example demonstrating colors 872 |----> simple_key.c -- A menu accessible with keyboard UP, DOWN 873 | -- arrows 874 |----> temp_leave.c -- Demonstrates temporarily leaving curses mode 875 |----> win_border.c -- Shows Creation of windows and borders 876 |----> with_chgat.c -- chgat() usage example 877 878 forms 879 | 880 |----> form_attrib.c -- Usage of field attributes 881 |----> form_options.c -- Usage of field options 882 |----> form_simple.c -- A simple form example 883 |----> form_win.c -- Demo of windows associated with forms 884 885 menus 886 | 887 |----> menu_attrib.c -- Usage of menu attributes 888 |----> menu_item_data.c -- Usage of item_name(), etc. functions 889 |----> menu_multi_column.c -- Creates multi columnar menus 890 |----> menu_scroll.c -- Demonstrates scrolling capability of menus 891 |----> menu_simple.c -- A simple menu accessed by arrow keys 892 |----> menu_toggle.c -- Creates multi valued menus and explains 893 | -- REQ_TOGGLE_ITEM 894 |----> menu_userptr.c -- Usage of user pointer 895 |----> menu_win.c -- Demo of windows associated with menus 896 897 panels 898 | 899 |----> panel_browse.c -- Panel browsing through tab. Usage of user 900 | -- pointer 901 |----> panel_hide.c -- Hiding and Un hiding of panels 902 |----> panel_resize.c -- Moving and resizing of panels 903 |----> panel_simple.c -- A simple panel example 904 905 perl 906 |----> 01-10.pl -- Perl equivalents of first ten example programs</pre> 907 <p>There is a top level Makefile included in the main 908 directory. It builds all the files and puts the 909 ready-to-use exes in demo/exe directory. You can also do 910 selective make by going into the corresponding directory. 911 Each directory contains a README file explaining the 912 purpose of each c file in the directory.</p> 913 914 <p>For every example, I have included path name for the 915 file relative to the examples directory.</p> 916 917 <p>If you prefer browsing individual programs, point your 918 browser to <a href= 919 "https://tldp.org/HOWTO/NCURSES-Programming-HOWTO/ncurses_programs/" 920 target= 921 "_top">https://tldp.org/HOWTO/NCURSES-Programming-HOWTO/ncurses_programs/</a></p> 922 923 <p>All the programs are released under the same license 924 that is used by ncurses (MIT-style). This gives you the 925 ability to do pretty much anything other than claiming them 926 as yours. Feel free to use them in your programs as 927 appropriate.</p> 928 </div> 929 930 <div class="SECT2"> 931 <hr> 932 933 <h3 class="SECT2"><a name="OTHERFORMATS" id= 934 "OTHERFORMATS">1.6. Other Formats of the document</a></h3> 935 936 <p>This howto is also available in various other formats on 937 the tldp.org site. Here are the links to other formats of 938 this document.</p> 939 940 <div class="SECT3"> 941 <hr> 942 943 <h4 class="SECT3"><a name="LISTFORMATS" id= 944 "LISTFORMATS">1.6.1. Readily available formats from 945 tldp.org</a></h4> 946 947 <ul> 948 <li> 949 <p><a href= 950 "https://www.ibiblio.org/pub/Linux/docs/HOWTO/other-formats/pdf/NCURSES-Programming-HOWTO.pdf" 951 target="_top">Acrobat PDF Format</a></p> 952 </li> 953 954 <li> 955 <p><a href= 956 "https://www.ibiblio.org/pub/Linux/docs/HOWTO/other-formats/ps/NCURSES-Programming-HOWTO.ps.gz" 957 target="_top">PostScript Format</a></p> 958 </li> 959 960 <li> 961 <p><a href= 962 "https://www.ibiblio.org/pub/Linux/docs/HOWTO/other-formats/html/NCURSES-Programming-HOWTO-html.tar.gz" 963 target="_top">In Multiple HTML pages</a></p> 964 </li> 965 966 <li> 967 <p><a href= 968 "https://www.ibiblio.org/pub/Linux/docs/HOWTO/other-formats/html_single/NCURSES-Programming-HOWTO.html" 969 target="_top">In One big HTML format</a></p> 970 </li> 971 </ul> 972 </div> 973 974 <div class="SECT3"> 975 <hr> 976 977 <h4 class="SECT3"><a name="BUILDSOURCE" id= 978 "BUILDSOURCE">1.6.2. Building from source</a></h4> 979 980 <p>If above links are broken or if you want to experiment 981 with sgml read on.</p> 982 983 <pre class= 984 "PROGRAMLISTING"> Get both the source and the tar,gzipped programs, available at 985 http://cvsview.tldp.org/index.cgi/LDP/howto/docbook/ 986 NCURSES-HOWTO/NCURSES-Programming-HOWTO.sgml 987 http://cvsview.tldp.org/index.cgi/LDP/howto/docbook/ 988 NCURSES-HOWTO/ncurses_programs.tar.gz 989 990 Unzip ncurses_programs.tar.gz with 991 tar zxvf ncurses_programs.tar.gz 992 993 Use jade to create various formats. For example if you just want to create 994 the multiple html files, you would use 995 jade -t sgml -i html -d <path to docbook html stylesheet> 996 NCURSES-Programming-HOWTO.sgml 997 to get pdf, first create a single html file of the HOWTO with 998 jade -t sgml -i html -d <path to docbook html stylesheet> -V nochunks 999 NCURSES-Programming-HOWTO.sgml > NCURSES-ONE-BIG-FILE.html 1000 then use htmldoc to get pdf file with 1001 htmldoc --size universal -t pdf --firstpage p1 -f <output file name.pdf> 1002 NCURSES-ONE-BIG-FILE.html 1003 for ps, you would use 1004 htmldoc --size universal -t ps --firstpage p1 -f <output file name.ps> 1005 NCURSES-ONE-BIG-FILE.html</pre> 1006 <p>See <a href= 1007 "https://www.tldp.org/LDP/LDP-Author-Guide/" target= 1008 "_top">LDP Author guide</a> for more details. If all else 1009 fails, mail me at <a href="ppadala@gmail.com" target= 1010 "_top">ppadala@gmail.com</a></p> 1011 </div> 1012 </div> 1013 1014 <div class="SECT2"> 1015 <hr> 1016 1017 <h3 class="SECT2"><a name="CREDITS" id="CREDITS">1.7. 1018 Credits</a></h3> 1019 1020 <p>I thank <a href="mailto:sharath_1@usa.net" target= 1021 "_top">Sharath</a> and Emre Akbas for helping me with few 1022 sections. The introduction was initially written by 1023 sharath. I rewrote it with few excerpts taken from his 1024 initial work. Emre helped in writing printw and scanw 1025 sections.</p> 1026 1027 <p>Perl equivalents of the example programs are contributed 1028 by <a href="mailto:Aratnaweera@virtusa.com" target= 1029 "_top">Anuradha Ratnaweera</a>.</p> 1030 1031 <p>Then comes <a href="mailto:parimi@ece.arizona.edu" 1032 target="_top">Ravi Parimi</a>, my dearest friend, who has 1033 been on this project before even one line was written. He 1034 constantly bombarded me with suggestions and patiently 1035 reviewed the whole text. He also checked each program on 1036 Linux and Solaris.</p> 1037 </div> 1038 1039 <div class="SECT2"> 1040 <hr> 1041 1042 <h3 class="SECT2"><a name="WISHLIST" id="WISHLIST">1.8. 1043 Wish List</a></h3> 1044 1045 <p>This is the wish list, in the order of priority. If you 1046 have a wish or you want to work on completing the wish, 1047 mail <a href="mailto:ppadala@gmail.com" target= 1048 "_top">me</a>.</p> 1049 1050 <ul> 1051 <li> 1052 <p>Add examples to last parts of forms section.</p> 1053 </li> 1054 1055 <li> 1056 <p>Prepare a Demo showing all the programs and allow 1057 the user to browse through description of each program. 1058 Let the user compile and see the program in action. A 1059 dialog based interface is preferred.</p> 1060 </li> 1061 1062 <li> 1063 <p>Add debug info. _tracef, _tracemouse stuff.</p> 1064 </li> 1065 1066 <li> 1067 <p>Accessing termcap, terminfo using functions provided 1068 by ncurses package.</p> 1069 </li> 1070 1071 <li> 1072 <p>Working on two terminals simultaneously.</p> 1073 </li> 1074 1075 <li> 1076 <p>Add more stuff to miscellaneous section.</p> 1077 </li> 1078 </ul> 1079 </div> 1080 1081 <div class="SECT2"> 1082 <hr> 1083 1084 <h3 class="SECT2"><a name="COPYRIGHT" id="COPYRIGHT">1.9. 1085 Copyright</a></h3> 1086 1087 <p>Copyright © 2001 by Pradeep Padala.</p> 1088 1089 <p>Permission is hereby granted, free of charge, to any 1090 person obtaining a copy of this software and associated 1091 documentation files (the "Software"), to deal in the 1092 Software without restriction, including without limitation 1093 the rights to use, copy, modify, merge, publish, 1094 distribute, distribute with modifications, sublicense, 1095 and/or sell copies of the Software, and to permit persons 1096 to whom the Software is furnished to do so, subject to the 1097 following conditions:</p> 1098 1099 <p>The above copyright notice and this permission notice 1100 shall be included in all copies or substantial portions of 1101 the Software.</p> 1102 1103 <p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 1104 ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 1105 THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 1106 PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ABOVE 1107 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1108 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 1109 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 1110 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</p> 1111 1112 <p>Except as contained in this notice, the name(s) of the 1113 above copyright holders shall not be used in advertising or 1114 otherwise to promote the sale, use or other dealings in 1115 this Software without prior written authorization.</p> 1116 </div> 1117 </div> 1118 1119 <div class="SECT1"> 1120 <hr> 1121 1122 <h2 class="SECT1"><a name="HELLOWORLD" id="HELLOWORLD">2. 1123 Hello World !!!</a></h2> 1124 1125 <p>Welcome to the world of curses. Before we plunge into the 1126 library and look into its various features, let's write a 1127 simple program and say hello to the world.</p> 1128 1129 <div class="SECT2"> 1130 <hr> 1131 1132 <h3 class="SECT2"><a name="COMPILECURSES" id= 1133 "COMPILECURSES">2.1. Compiling With the NCURSES Library</a></h3> 1134 1135 <p>To use ncurses library functions, you have to include 1136 ncurses.h in your programs. To link the program with 1137 ncurses the flag -lncurses should be added.</p> 1138 1139 <pre class="PROGRAMLISTING"> #include <ncurses.h> 1140 . 1141 . 1142 . 1143 1144 compile and link: gcc <program file> -lncurses</pre> 1145 <div class="EXAMPLE"> 1146 <a name="BHW" id="BHW"></a> 1147 <p><b>Example 1. The Hello World !!! Program</b> 1148 </p> 1149 1150 <pre class="PROGRAMLISTING"><span class= 1151 "INLINEMEDIAOBJECT">#include <curses.h> 1152 1153int main() 1154{ 1155 initscr(); /* Start curses mode */ 1156 printw("Hello World !!!"); /* Print Hello World */ 1157 refresh(); /* Print it on to the real screen */ 1158 getch(); /* Wait for user input */ 1159 endwin(); /* End curses mode */ 1160 1161 return 0; 1162}</span></pre> 1163 </div> 1164 </div> 1165 1166 <div class="SECT2"> 1167 <hr> 1168 1169 <h3 class="SECT2"><a name="DISSECTION" id="DISSECTION">2.2. 1170 Dissection</a></h3> 1171 1172 <p>The above program prints "Hello World !!!" to the screen 1173 and exits. This program shows how to initialize curses and 1174 do screen manipulation and end curses mode. Let's dissect 1175 it line by line.</p> 1176 1177 <div class="SECT3"> 1178 <hr> 1179 1180 <h4 class="SECT3"><a name="ABOUT-INITSCR" id= 1181 "ABOUT-INITSCR">2.2.1. About initscr()</a></h4> 1182 1183 <p>The function initscr() initializes the terminal in 1184 curses mode. In some implementations, it clears the 1185 screen and presents a blank screen. To do any screen 1186 manipulation using curses package this has to be called 1187 first. This function initializes the curses system and 1188 allocates memory for our present window (called 1189 <tt class="LITERAL">stdscr</tt>) and some other 1190 data-structures. Under extreme cases this function might 1191 fail due to insufficient memory to allocate memory for 1192 curses library's data structures.</p> 1193 1194 <p>After this is done, we can do a variety of 1195 initializations to customize our curses settings. These 1196 details will be explained <a href="#INIT">later</a> .</p> 1197 </div> 1198 1199 <div class="SECT3"> 1200 <hr> 1201 1202 <h4 class="SECT3"><a name="MYST-REFRESH" id= 1203 "MYST-REFRESH">2.2.2. The mysterious refresh()</a></h4> 1204 1205 <p>The next line printw prints the string "Hello World 1206 !!!" on to the screen. This function is analogous to 1207 normal printf in all respects except that it prints the 1208 data on a window called stdscr at the current (y,x) 1209 co-ordinates. Since our present co-ordinates are at 0,0 1210 the string is printed at the left hand corner of the 1211 window.</p> 1212 1213 <p>This brings us to that mysterious refresh(). Well, 1214 when we called printw the data is actually written to an 1215 imaginary window, which is not updated on the screen yet. 1216 The job of printw is to update a few flags and data 1217 structures and write the data to a buffer corresponding 1218 to stdscr. In order to show it on the screen, we need to 1219 call refresh() and tell the curses system to dump the 1220 contents on the screen.</p> 1221 1222 <p>The philosophy behind all this is to allow the 1223 programmer to do multiple updates on the imaginary screen 1224 or windows and do a refresh once all his screen update is 1225 done. refresh() checks the window and updates only the 1226 portion which has been changed. This improves performance 1227 and offers greater flexibility too. But, it is sometimes 1228 frustrating to beginners. A common mistake committed by 1229 beginners is to forget to call refresh() after they did 1230 some update through printw() class of functions. I still 1231 forget to add it sometimes :-)</p> 1232 </div> 1233 1234 <div class="SECT3"> 1235 <hr> 1236 1237 <h4 class="SECT3"><a name="ABOUT-ENDWIN" id= 1238 "ABOUT-ENDWIN">2.2.3. About endwin()</a></h4> 1239 1240 <p>And finally don't forget to end the curses mode. 1241 Otherwise your terminal might behave strangely after the 1242 program quits. endwin() frees the memory taken by curses 1243 sub-system and its data structures and puts the terminal 1244 in normal mode. This function must be called after you 1245 are done with the curses mode.</p> 1246 </div> 1247 </div> 1248 </div> 1249 1250 <div class="SECT1"> 1251 <hr> 1252 1253 <h2 class="SECT1"><a name="GORY" id="GORY">3. The Gory 1254 Details</a></h2> 1255 1256 <p>Now that we have seen how to write a simple curses program 1257 let's get into the details. There are many functions that 1258 help customize what you see on screen and many features which 1259 can be put to full use.</p> 1260 1261 <p>Here we go...</p> 1262 </div> 1263 1264 <div class="SECT1"> 1265 <hr> 1266 1267 <h2 class="SECT1"><a name="INIT" id="INIT">4. 1268 Initialization</a></h2> 1269 1270 <p>We now know that to initialize curses system the function 1271 initscr() has to be called. There are functions which can be 1272 called after this initialization to customize our curses 1273 session. We may ask the curses system to set the terminal in 1274 raw mode or initialize color or initialize the mouse, etc. 1275 Let's discuss some of the functions that are normally called 1276 immediately after initscr();</p> 1277 1278 <div class="SECT2"> 1279 <hr> 1280 1281 <h3 class="SECT2"><a name="ABOUTINIT" id="ABOUTINIT">4.1. 1282 Initialization functions</a></h3> 1283 </div> 1284 1285 <div class="SECT2"> 1286 <hr> 1287 1288 <h3 class="SECT2"><a name="RAWCBREAK" id="RAWCBREAK">4.2. 1289 raw() and cbreak()</a></h3> 1290 1291 <p>Normally the terminal driver buffers the characters a 1292 user types until a new line or carriage return is 1293 encountered. But most programs require that the characters 1294 be available as soon as the user types them. The above two 1295 functions are used to disable line buffering. The 1296 difference between these two functions is in the way 1297 control characters like suspend (CTRL-Z), interrupt and 1298 quit (CTRL-C) are passed to the program. In the raw() mode 1299 these characters are directly passed to the program without 1300 generating a signal. In the <tt class= 1301 "LITERAL">cbreak()</tt> mode these control characters are 1302 interpreted as any other character by the terminal driver. 1303 I personally prefer to use raw() as I can exercise greater 1304 control over what the user does.</p> 1305 </div> 1306 1307 <div class="SECT2"> 1308 <hr> 1309 1310 <h3 class="SECT2"><a name="ECHONOECHO" id="ECHONOECHO">4.3. 1311 echo() and noecho()</a></h3> 1312 1313 <p>These functions control the echoing of characters typed 1314 by the user to the terminal. <tt class= 1315 "LITERAL">noecho()</tt> switches off echoing. The reason 1316 you might want to do this is to gain more control over 1317 echoing or to suppress unnecessary echoing while taking 1318 input from the user through the getch(), etc. functions. 1319 Most of the interactive programs call <tt class= 1320 "LITERAL">noecho()</tt> at initialization and do the 1321 echoing of characters in a controlled manner. It gives the 1322 programmer the flexibility of echoing characters at any 1323 place in the window without updating current (y,x) 1324 co-ordinates.</p> 1325 </div> 1326 1327 <div class="SECT2"> 1328 <hr> 1329 1330 <h3 class="SECT2"><a name="KEYPAD" id="KEYPAD">4.4. 1331 keypad()</a></h3> 1332 1333 <p>This is my favorite initialization function. It enables 1334 the reading of function keys like F1, F2, arrow keys, etc. 1335 Almost every interactive program enables this, as arrow 1336 keys are a major part of any User Interface. Do <tt class= 1337 "LITERAL">keypad(stdscr, TRUE)</tt> to enable this feature 1338 for the regular screen (stdscr). You will learn more about 1339 key management in later sections of this document.</p> 1340 </div> 1341 1342 <div class="SECT2"> 1343 <hr> 1344 1345 <h3 class="SECT2"><a name="HALFDELAY" id="HALFDELAY">4.5. 1346 halfdelay()</a></h3> 1347 1348 <p>This function, though not used very often, is a useful 1349 one at times. halfdelay()is called to enable the half-delay 1350 mode, which is similar to the cbreak() mode in that 1351 characters typed are immediately available to program. 1352 However, it waits for 'X' tenths of a second for input and 1353 then returns ERR, if no input is available. 'X' is the 1354 timeout value passed to the function halfdelay(). This 1355 function is useful when you want to ask the user for input, 1356 and if he doesn't respond with in certain time, we can do 1357 some thing else. One possible example is a timeout at the 1358 password prompt.</p> 1359 </div> 1360 1361 <div class="SECT2"> 1362 <hr> 1363 1364 <h3 class="SECT2"><a name="MISCINIT" id="MISCINIT">4.6. 1365 Miscellaneous Initialization functions</a></h3> 1366 1367 <p>There are few more functions which are called at 1368 initialization to customize curses behavior. They are not 1369 used as extensively as those mentioned above. Some of them 1370 are explained where appropriate.</p> 1371 </div> 1372 1373 <div class="SECT2"> 1374 <hr> 1375 1376 <h3 class="SECT2"><a name="INITEX" id="INITEX">4.7. An 1377 Example</a></h3> 1378 1379 <p>Let's write a program which will clarify the usage of 1380 these functions.</p> 1381 1382 <div class="EXAMPLE"> 1383 <a name="BINFU" id="BINFU"></a> 1384 <p><b>Example 2. Initialization Function Usage 1385 example</b> 1386 </p> 1387 1388 <pre class="PROGRAMLISTING"><span class= 1389 "INLINEMEDIAOBJECT">#include <curses.h> 1390 1391int main() 1392{ int ch; 1393 1394 initscr(); /* Start curses mode */ 1395 raw(); /* Line buffering disabled */ 1396 keypad(stdscr, TRUE); /* We get F1, F2 etc.. */ 1397 noecho(); /* Don't echo() while we do getch */ 1398 1399 printw("Type any character to see it in bold\n"); 1400 ch = getch(); /* If raw() hadn't been called 1401 * we have to press enter before it 1402 * gets to the program */ 1403 if(ch == KEY_F(1)) /* Without keypad enabled this will */ 1404 printw("F1 Key pressed");/* not get to us either */ 1405 /* Without noecho() some ugly escape 1406 * characters might have been printed 1407 * on screen */ 1408 else 1409 { printw("The pressed key is "); 1410 attron(A_BOLD); 1411 printw("%c", ch); 1412 attroff(A_BOLD); 1413 } 1414 refresh(); /* Print it on to the real screen */ 1415 getch(); /* Wait for user input */ 1416 endwin(); /* End curses mode */ 1417 1418 return 0; 1419}</span></pre> 1420 </div> 1421 1422 <p>This program is self-explanatory. But I used functions 1423 which aren't explained yet. The function <tt class= 1424 "LITERAL">getch()</tt> is used to get a character from 1425 user. It is equivalent to normal <tt class= 1426 "LITERAL">getchar()</tt> except that we can disable the 1427 line buffering to avoid <enter> after input. Look for 1428 more about <tt class="LITERAL">getch()</tt>and reading keys 1429 in the <a href="#KEYS">key management section</a> . The 1430 functions attron and attroff are used to switch some 1431 attributes on and off respectively. In the example I used 1432 them to print the character in bold. These functions are 1433 explained in detail later.</p> 1434 </div> 1435 </div> 1436 1437 <div class="SECT1"> 1438 <hr> 1439 1440 <h2 class="SECT1"><a name="AWORDWINDOWS" id="AWORDWINDOWS">5. 1441 A Word about Windows</a></h2> 1442 1443 <p>Before we plunge into the myriad ncurses functions, let me 1444 clear few things about windows. Windows are explained in 1445 detail in following <a href="#WINDOWS">sections</a></p> 1446 1447 <p>A Window is an imaginary screen defined by curses system. 1448 A window does not mean a bordered window which you usually 1449 see on Win9X platforms. When curses is initialized, it 1450 creates a default window named <tt class= 1451 "LITERAL">stdscr</tt> which represents your 80x25 (or the 1452 size of window in which you are running) screen. If you are 1453 doing simple tasks like printing few strings, reading input, 1454 etc., you can safely use this single window for all of your 1455 purposes. You can also create windows and call functions 1456 which explicitly work on the specified window.</p> 1457 1458 <p>For example, if you call</p> 1459 1460 <pre class="PROGRAMLISTING"> printw("Hi There !!!"); 1461 refresh();</pre> 1462 <p>It prints the string on stdscr at the present cursor 1463 position. Similarly the call to refresh(), works on stdscr 1464 only.</p> 1465 1466 <p>Say you have created <a href="#WINDOWS">windows</a> then 1467 you have to call a function with a 'w' added to the usual 1468 function.</p> 1469 1470 <pre class="PROGRAMLISTING"> wprintw(win, "Hi There !!!"); 1471 wrefresh(win);</pre> 1472 <p>As you will see in the rest of the document, naming of 1473 functions follow the same convention. For each function there 1474 usually are three more functions.</p> 1475 1476 <pre class= 1477 "PROGRAMLISTING"> printw(string); /* Print on stdscr at present cursor position */ 1478 mvprintw(y, x, string);/* Move to (y, x) then print string */ 1479 wprintw(win, string); /* Print on window win at present cursor position */ 1480 /* in the window */ 1481 mvwprintw(win, y, x, string); /* Move to (y, x) relative to window */ 1482 /* co-ordinates and then print */</pre> 1483 <p>Usually the w-less functions are macros which expand to 1484 corresponding w-function with stdscr as the window 1485 parameter.</p> 1486 </div> 1487 1488 <div class="SECT1"> 1489 <hr> 1490 1491 <h2 class="SECT1"><a name="PRINTW" id="PRINTW">6. Output 1492 functions</a></h2> 1493 1494 <p>I guess you can't wait any more to see some action. Back 1495 to our odyssey of curses functions. Now that curses is 1496 initialized, let's interact with world.</p> 1497 1498 <p>There are three classes of functions which you can use to 1499 do output on screen.</p> 1500 1501 <ol type="1"> 1502 <li> 1503 <p>addch() class: Print single character with 1504 attributes</p> 1505 </li> 1506 1507 <li> 1508 <p>printw() class: Print formatted output similar to 1509 printf()</p> 1510 </li> 1511 1512 <li> 1513 <p>addstr() class: Print strings</p> 1514 </li> 1515 </ol> 1516 1517 <p>These functions can be used interchangeably and it is a 1518 matter of style as to which class is used. Let's see each one 1519 in detail.</p> 1520 1521 <div class="SECT2"> 1522 <hr> 1523 1524 <h3 class="SECT2"><a name="ADDCHCLASS" id="ADDCHCLASS">6.1. 1525 addch() class of functions</a></h3> 1526 1527 <p>These functions put a single character into the current 1528 cursor location and advance the position of the cursor. You 1529 can give the character to be printed but they usually are 1530 used to print a character with some attributes. Attributes 1531 are explained in detail in later <a href= 1532 "#ATTRIB">sections</a> of the document. If a character is 1533 associated with an attribute(bold, reverse video etc.), 1534 when curses prints the character, it is printed in that 1535 attribute.</p> 1536 1537 <p>In order to combine a character with some attributes, 1538 you have two options:</p> 1539 1540 <ul> 1541 <li> 1542 <p>By OR'ing a single character with the desired 1543 attribute macros. These attribute macros could be found 1544 in the header file <tt class="LITERAL">ncurses.h</tt>. 1545 For example, you want to print a character ch(of type 1546 char) bold and underlined, you would call addch() as 1547 below.</p> 1548 1549 <pre class= 1550 "PROGRAMLISTING"> addch(ch | A_BOLD | A_UNDERLINE);</pre> 1551 </li> 1552 1553 <li> 1554 <p>By using functions like <tt class= 1555 "LITERAL">attrset(),attron(),attroff()</tt>. These 1556 functions are explained in the <a href= 1557 "#ATTRIB">Attributes</a> section. Briefly, they 1558 manipulate the current attributes of the given window. 1559 Once set, the character printed in the window are 1560 associated with the attributes until it is turned 1561 off.</p> 1562 </li> 1563 </ul> 1564 1565 <p>Additionally, <tt class="LITERAL">curses</tt> provides 1566 some special characters for character-based graphics. You 1567 can draw tables, horizontal or vertical lines, etc. You can 1568 find all available characters in the header file <tt class= 1569 "LITERAL">ncurses.h</tt>. Try looking for macros beginning 1570 with <tt class="LITERAL">ACS_</tt> in this file.</p> 1571 </div> 1572 1573 <div class="SECT2"> 1574 <hr> 1575 1576 <h3 class="SECT2"><a name="AEN303" id="AEN303">6.2. 1577 mvaddch(), waddch() and mvwaddch()</a></h3> 1578 1579 <p><tt class="LITERAL">mvaddch()</tt> is used to move the 1580 cursor to a given point, and then print. Thus, the 1581 calls:</p> 1582 1583 <pre class= 1584 "PROGRAMLISTING"> move(row,col); /* moves the cursor to row<span class="emphasis"><i class="EMPHASIS">th</i></span> row and col<span class="emphasis"><i class="EMPHASIS">th</i></span> column */ 1585 addch(ch);</pre>can be replaced by 1586 1587 <pre class="PROGRAMLISTING"> mvaddch(row,col,ch);</pre> 1588 <p><tt class="LITERAL">waddch()</tt> is similar to 1589 <tt class="LITERAL">addch()</tt>, except that it adds a 1590 character into the given window. (Note that <tt class= 1591 "LITERAL">addch()</tt> adds a character into the window 1592 <tt class="LITERAL">stdscr</tt>.)</p> 1593 1594 <p>In a similar fashion <tt class="LITERAL">mvwaddch()</tt> 1595 function is used to add a character into the given window 1596 at the given coordinates.</p> 1597 1598 <p>Now, we are familiar with the basic output function 1599 <tt class="LITERAL">addch()</tt>. But, if we want to print 1600 a string, it would be very annoying to print it character 1601 by character. Fortunately, <tt class="LITERAL">ncurses</tt> 1602 provides <tt class="LITERAL">printf</tt><span class= 1603 "emphasis"><i class="EMPHASIS">-like</i></span> or 1604 <tt class="LITERAL">puts</tt><span class= 1605 "emphasis"><i class="EMPHASIS">-like</i></span> 1606 functions.</p> 1607 </div> 1608 1609 <div class="SECT2"> 1610 <hr> 1611 1612 <h3 class="SECT2"><a name="PRINTWCLASS" id= 1613 "PRINTWCLASS">6.3. printw() class of functions</a></h3> 1614 1615 <p>These functions are similar to <tt class= 1616 "LITERAL">printf()</tt> with the added capability of 1617 printing at any position on the screen.</p> 1618 1619 <div class="SECT3"> 1620 <hr> 1621 1622 <h4 class="SECT3"><a name="PRINTWMVPRINTW" id= 1623 "PRINTWMVPRINTW">6.3.1. printw() and mvprintw</a></h4> 1624 1625 <p>These two functions work much like <tt class= 1626 "LITERAL">printf()</tt>. <tt class= 1627 "LITERAL">mvprintw()</tt> can be used to move the cursor 1628 to a position and then print. If you want to move the 1629 cursor first and then print using <tt class= 1630 "LITERAL">printw()</tt> function, use <tt class= 1631 "LITERAL">move()</tt> first and then use <tt class= 1632 "LITERAL">printw()</tt> though I see no point why one 1633 should avoid using <tt class="LITERAL">mvprintw()</tt>, 1634 you have the flexibility to manipulate.</p> 1635 </div> 1636 1637 <div class="SECT3"> 1638 <hr> 1639 1640 <h4 class="SECT3"><a name="WPRINTWMVWPRINTW" id= 1641 "WPRINTWMVWPRINTW">6.3.2. wprintw() and mvwprintw</a></h4> 1642 1643 <p>These two functions are similar to above two except 1644 that they print in the corresponding window given as 1645 argument.</p> 1646 </div> 1647 1648 <div class="SECT3"> 1649 <hr> 1650 1651 <h4 class="SECT3"><a name="VWPRINTW" id="VWPRINTW">6.3.3. 1652 vw_printw()</a></h4> 1653 1654 <p>This function is similar to <tt class= 1655 "LITERAL">vprintf()</tt>. This can be used when variable 1656 number of arguments are to be printed.</p> 1657 </div> 1658 1659 <div class="SECT3"> 1660 <hr> 1661 1662 <h4 class="SECT3"><a name="SIMPLEPRINTWEX" id= 1663 "SIMPLEPRINTWEX">6.3.4. A Simple printw example</a></h4> 1664 1665 <div class="EXAMPLE"> 1666 <a name="BPREX" id="BPREX"></a> 1667 <p><b>Example 3. A Simple printw example</b> 1668 </p> 1669 1670 <pre class="PROGRAMLISTING"><span class= 1671 "INLINEMEDIAOBJECT">#include <curses.h> 1672#include <string.h> 1673 1674int main() 1675{ 1676 char mesg[]="Just a string"; /* message to be appeared on the screen */ 1677 int row,col; /* to store the number of rows and * 1678 * the number of columns of the screen */ 1679 initscr(); /* start the curses mode */ 1680 getmaxyx(stdscr,row,col); /* get the number of rows and columns */ 1681 mvprintw(row/2,(col-strlen(mesg))/2,"%s",mesg); 1682 /* print the message at the center of the screen */ 1683 mvprintw(row-2,0,"This screen has %d rows and %d columns\n",row,col); 1684 printw("Try resizing your window(if possible) and then run this program again"); 1685 refresh(); 1686 getch(); 1687 endwin(); 1688 1689 return 0; 1690}</span></pre> 1691 </div> 1692 1693 <p>Above program demonstrates how easy it is to use 1694 <tt class="LITERAL">printw</tt>. You just feed the 1695 coordinates and the message to be appeared on the screen, 1696 then it does what you want.</p> 1697 1698 <p>The above program introduces us to a new function 1699 <tt class="LITERAL">getmaxyx()</tt>, a macro defined in 1700 <tt class="LITERAL">ncurses.h</tt>. It gives the number 1701 of columns and the number of rows in a given window. 1702 <tt class="LITERAL">getmaxyx()</tt> does this by updating 1703 the variables given to it. Since <tt class= 1704 "LITERAL">getmaxyx()</tt> is not a function we don't pass 1705 pointers to it, we just give two integer variables.</p> 1706 </div> 1707 </div> 1708 1709 <div class="SECT2"> 1710 <hr> 1711 1712 <h3 class="SECT2"><a name="ADDSTRCLASS" id= 1713 "ADDSTRCLASS">6.4. addstr() class of functions</a></h3> 1714 1715 <p><tt class="LITERAL">addstr()</tt> is used to put a 1716 character string into a given window. This function is 1717 similar to calling <tt class="LITERAL">addch()</tt> once 1718 for each character in a given string. This is true for all 1719 output functions. There are other functions from this 1720 family such as <tt class= 1721 "LITERAL">mvaddstr(),mvwaddstr()</tt> and <tt class= 1722 "LITERAL">waddstr()</tt>, which obey the naming convention 1723 of curses.(e.g. mvaddstr() is similar to the respective 1724 calls move() and then addstr().) Another function of this 1725 family is addnstr(), which takes an integer parameter(say 1726 n) additionally. This function puts at most n characters 1727 into the screen. If n is negative, then the entire string 1728 will be added.</p> 1729 </div> 1730 1731 <div class="SECT2"> 1732 <hr> 1733 1734 <h3 class="SECT2"><a name="ACAUTION" id="ACAUTION">6.5. A 1735 word of caution</a></h3> 1736 1737 <p>All these functions take y co-ordinate first and then x 1738 in their arguments. A common mistake by beginners is to 1739 pass x,y in that order. If you are doing too many 1740 manipulations of (y,x) co-ordinates, think of dividing the 1741 screen into windows and manipulate each one separately. 1742 Windows are explained in the <a href="#WINDOWS">windows</a> 1743 section.</p> 1744 </div> 1745 </div> 1746 1747 <div class="SECT1"> 1748 <hr> 1749 1750 <h2 class="SECT1"><a name="SCANW" id="SCANW">7. Input 1751 functions</a></h2> 1752 1753 <p>Well, printing without taking input, is boring. Let's see 1754 functions which allow us to get input from user. These 1755 functions also can be divided into three categories.</p> 1756 1757 <ol type="1"> 1758 <li> 1759 <p>getch() class: Get a character</p> 1760 </li> 1761 1762 <li> 1763 <p>scanw() class: Get formatted input</p> 1764 </li> 1765 1766 <li> 1767 <p>getstr() class: Get strings</p> 1768 </li> 1769 </ol> 1770 1771 <div class="SECT2"> 1772 <hr> 1773 1774 <h3 class="SECT2"><a name="GETCHCLASS" id="GETCHCLASS">7.1. 1775 getch() class of functions</a></h3> 1776 1777 <p>These functions read a single character from the 1778 terminal. But there are several subtle facts to consider. 1779 For example if you don't use the function cbreak(), curses 1780 will not read your input characters contiguously but will 1781 begin read them only after a new line or an EOF is 1782 encountered. In order to avoid this, the cbreak() function 1783 must used so that characters are immediately available to 1784 your program. Another widely used function is noecho(). As 1785 the name suggests, when this function is set (used), the 1786 characters that are keyed in by the user will not show up 1787 on the screen. The two functions cbreak() and noecho() are 1788 typical examples of key management. Functions of this genre 1789 are explained in the <a href="#KEYS">key management 1790 section</a> .</p> 1791 </div> 1792 1793 <div class="SECT2"> 1794 <hr> 1795 1796 <h3 class="SECT2"><a name="SCANWCLASS" id="SCANWCLASS">7.2. 1797 scanw() class of functions</a></h3> 1798 1799 <p>These functions are similar to <tt class= 1800 "LITERAL">scanf()</tt> with the added capability of getting 1801 the input from any location on the screen.</p> 1802 1803 <div class="SECT3"> 1804 <hr> 1805 1806 <h4 class="SECT3"><a name="SCANWMVSCANW" id= 1807 "SCANWMVSCANW">7.2.1. scanw() and mvscanw</a></h4> 1808 1809 <p>The usage of these functions is similar to that of 1810 <tt class="LITERAL">sscanf()</tt>, where the line to be 1811 scanned is provided by <tt class="LITERAL">wgetstr()</tt> 1812 function. That is, these functions call to <tt class= 1813 "LITERAL">wgetstr()</tt> function(explained below) and 1814 uses the resulting line for a scan.</p> 1815 </div> 1816 1817 <div class="SECT3"> 1818 <hr> 1819 1820 <h4 class="SECT3"><a name="WSCANWMVWSCANW" id= 1821 "WSCANWMVWSCANW">7.2.2. wscanw() and mvwscanw()</a></h4> 1822 1823 <p>These are similar to above two functions except that 1824 they read from a window, which is supplied as one of the 1825 arguments to these functions.</p> 1826 </div> 1827 1828 <div class="SECT3"> 1829 <hr> 1830 1831 <h4 class="SECT3"><a name="VWSCANW" id="VWSCANW">7.2.3. 1832 vw_scanw()</a></h4> 1833 1834 <p>This function is similar to <tt class= 1835 "LITERAL">vscanf()</tt>. This can be used when a variable 1836 number of arguments are to be scanned.</p> 1837 </div> 1838 </div> 1839 1840 <div class="SECT2"> 1841 <hr> 1842 1843 <h3 class="SECT2"><a name="GETSTRCLASS" id= 1844 "GETSTRCLASS">7.3. getstr() class of functions</a></h3> 1845 1846 <p>These functions are used to get strings from the 1847 terminal. In essence, this function performs the same task 1848 as would be achieved by a series of calls to <tt class= 1849 "LITERAL">getch()</tt> until a newline, carriage return, or 1850 end-of-file is received. The resulting string of characters 1851 are pointed to by <tt class="LITERAL">str</tt>, which is a 1852 character pointer provided by the user.</p> 1853 </div> 1854 1855 <div class="SECT2"> 1856 <hr> 1857 1858 <h3 class="SECT2"><a name="GETSTREX" id="GETSTREX">7.4. 1859 Some examples</a></h3> 1860 1861 <div class="EXAMPLE"> 1862 <a name="BSCEX" id="BSCEX"></a> 1863 <p><b>Example 4. A Simple scanw example</b> 1864 </p> 1865 1866 <pre class="PROGRAMLISTING"><span class= 1867 "INLINEMEDIAOBJECT">#include <curses.h> 1868#include <string.h> 1869 1870int main() 1871{ 1872 char mesg[]="Enter a string: "; /* message to be appeared on the screen */ 1873 char str[80]; 1874 int row,col; /* to store the number of rows and * 1875 * the number of columns of the screen */ 1876 initscr(); /* start the curses mode */ 1877 getmaxyx(stdscr,row,col); /* get the number of rows and columns */ 1878 mvprintw(row/2,(col-strlen(mesg))/2,"%s",mesg); 1879 /* print the message at the center of the screen */ 1880 getstr(str); 1881 mvprintw(LINES - 2, 0, "You Entered: %s", str); 1882 getch(); 1883 endwin(); 1884 1885 return 0; 1886}</span></pre> 1887 </div> 1888 </div> 1889 </div> 1890 1891 <div class="SECT1"> 1892 <hr> 1893 1894 <h2 class="SECT1"><a name="ATTRIB" id="ATTRIB">8. 1895 Attributes</a></h2> 1896 1897 <p>We have seen an example of how attributes can be used to 1898 print characters with some special effects. Attributes, when 1899 set prudently, can present information in an easy, 1900 understandable manner. The following program takes a C file 1901 as input and prints the file with comments in bold. Scan 1902 through the code.</p> 1903 1904 <div class="EXAMPLE"> 1905 <a name="BSIAT" id="BSIAT"></a> 1906 <p><b>Example 5. A Simple Attributes example</b> 1907 </p> 1908 1909 <pre class="PROGRAMLISTING"><span class= 1910 "INLINEMEDIAOBJECT">/* pager functionality by Joseph Spainhour" <spainhou@bellsouth.net> */ 1911#include <curses.h> 1912#include <stdlib.h> 1913 1914int main(int argc, char *argv[]) 1915{ 1916 int ch, prev, row, col; 1917 prev = EOF; 1918 FILE *fp; 1919 int y, x; 1920 1921 if(argc != 2) 1922 { 1923 printf("Usage: %s <a c file name>\n", argv[0]); 1924 exit(1); 1925 } 1926 fp = fopen(argv[1], "r"); 1927 if(fp == NULL) 1928 { 1929 perror("Cannot open input file"); 1930 exit(1); 1931 } 1932 initscr(); /* Start curses mode */ 1933 getmaxyx(stdscr, row, col); /* find the boundaries of the screeen */ 1934 while((ch = fgetc(fp)) != EOF) /* read the file till we reach the end */ 1935 { 1936 getyx(stdscr, y, x); /* get the current cursor position */ 1937 if(y == (row - 1)) /* are we are at the end of the screen */ 1938 { 1939 printw("<-Press Any Key->"); /* tell the user to press a key */ 1940 getch(); 1941 clear(); /* clear the screen */ 1942 move(0, 0); /* start at the beginning of the screen */ 1943 } 1944 if(prev == '/' && ch == '*') /* If it is / and * then only 1945 * switch bold on */ 1946 { 1947 attron(A_BOLD); /* cut bold on */ 1948 getyx(stdscr, y, x); /* get the current cursor position */ 1949 move(y, x - 1); /* back up one space */ 1950 printw("%c%c", '/', ch); /* The actual printing is done here */ 1951 } 1952 else 1953 printw("%c", ch); 1954 refresh(); 1955 if(prev == '*' && ch == '/') 1956 attroff(A_BOLD); /* Switch it off once we got * 1957 * and then / */ 1958 prev = ch; 1959 } 1960 endwin(); /* End curses mode */ 1961 fclose(fp); 1962 return 0; 1963}</span></pre> 1964 </div> 1965 1966 <p>Don't worry about all those initialization and other crap. 1967 Concentrate on the while loop. It reads each character in the 1968 file and searches for the pattern /*. Once it spots the 1969 pattern, it switches the BOLD attribute on with <tt class= 1970 "LITERAL">attron()</tt> . When we get the pattern */ it is 1971 switched off by <tt class="LITERAL">attroff()</tt> .</p> 1972 1973 <p>The above program also introduces us to two useful 1974 functions <tt class="LITERAL">getyx()</tt> and <tt class= 1975 "LITERAL">move()</tt>. The first function gets the 1976 co-ordinates of the present cursor into the variables y, x. 1977 Since getyx() is a macro we don't have to pass pointers to 1978 variables. The function <tt class="LITERAL">move()</tt> moves 1979 the cursor to the co-ordinates given to it.</p> 1980 1981 <p>The above program is really a simple one which doesn't do 1982 much. On these lines one could write a more useful program 1983 which reads a C file, parses it and prints it in different 1984 colors. One could even extend it to other languages as 1985 well.</p> 1986 1987 <div class="SECT2"> 1988 <hr> 1989 1990 <h3 class="SECT2"><a name="ATTRIBDETAILS" id= 1991 "ATTRIBDETAILS">8.1. The details</a></h3> 1992 1993 <p>Let's get into more details of attributes. The functions 1994 <tt class="LITERAL">attron(), attroff(), attrset()</tt> , 1995 and their sister functions <tt class= 1996 "LITERAL">attr_get()</tt>, etc. can be used to switch 1997 attributes on/off , get attributes and produce a colorful 1998 display.</p> 1999 2000 <p>The functions attron and attroff take a bit-mask of 2001 attributes and switch them on or off, respectively. The 2002 following video attributes, which are defined in 2003 <curses.h> can be passed to these functions.</p> 2004 2005 <pre class="PROGRAMLISTING"> 2006 A_NORMAL Normal display (no highlight) 2007 A_STANDOUT Best highlighting mode of the terminal. 2008 A_UNDERLINE Underlining 2009 A_REVERSE Reverse video 2010 A_BLINK Blinking 2011 A_DIM Half bright 2012 A_BOLD Extra bright or bold 2013 A_PROTECT Protected mode 2014 A_INVIS Invisible or blank mode 2015 A_ALTCHARSET Alternate character set 2016 A_CHARTEXT Bit-mask to extract a character 2017 COLOR_PAIR(n) Color-pair number n 2018 </pre> 2019 <p>The last one is the most colorful one :-) Colors are 2020 explained in the <a href="#color" target="_top">next 2021 sections</a>.</p> 2022 2023 <p>We can OR(|) any number of above attributes to get a 2024 combined effect. If you wanted reverse video with blinking 2025 characters you can use</p> 2026 2027 <pre class= 2028 "PROGRAMLISTING"> attron(A_REVERSE | A_BLINK);</pre> 2029 </div> 2030 2031 <div class="SECT2"> 2032 <hr> 2033 2034 <h3 class="SECT2"><a name="ATTRONVSATTRSET" id= 2035 "ATTRONVSATTRSET">8.2. attron() vs attrset()</a></h3> 2036 2037 <p>Then what is the difference between attron() and 2038 attrset()? attrset sets the attributes of window whereas 2039 attron just switches on the attribute given to it. So 2040 attrset() fully overrides whatever attributes the window 2041 previously had and sets it to the new attribute(s). 2042 Similarly attroff() just switches off the attribute(s) 2043 given to it as an argument. This gives us the flexibility 2044 of managing attributes easily.But if you use them 2045 carelessly you may loose track of what attributes the 2046 window has and garble the display. This is especially true 2047 while managing menus with colors and highlighting. So 2048 decide on a consistent policy and stick to it. You can 2049 always use <tt class="LITERAL">standend()</tt> which is 2050 equivalent to <tt class="LITERAL">attrset(A_NORMAL)</tt> 2051 which turns off all attributes and brings you to normal 2052 mode.</p> 2053 </div> 2054 2055 <div class="SECT2"> 2056 <hr> 2057 2058 <h3 class="SECT2"><a name="ATTRGET" id="ATTRGET">8.3. 2059 attr_get()</a></h3> 2060 2061 <p>The function attr_get() gets the current attributes and 2062 color pair of the window. Though we might not use this as 2063 often as the above functions, this is useful in scanning 2064 areas of screen. Say we wanted to do some complex update on 2065 screen and we are not sure what attribute each character is 2066 associated with. Then this function can be used with either 2067 attrset or attron to produce the desired effect.</p> 2068 </div> 2069 2070 <div class="SECT2"> 2071 <hr> 2072 2073 <h3 class="SECT2"><a name="ATTRFUNCS" id="ATTRFUNCS">8.4. 2074 attr_ functions</a></h3> 2075 2076 <p>There are series of functions like attr_set(), attr_on, 2077 etc. These are similar to above functions except that they 2078 take parameters of type <tt class= 2079 "LITERAL">attr_t</tt>.</p> 2080 </div> 2081 2082 <div class="SECT2"> 2083 <hr> 2084 2085 <h3 class="SECT2"><a name="WATTRFUNCS" id="WATTRFUNCS">8.5. 2086 wattr functions</a></h3> 2087 2088 <p>For each of the above functions we have a corresponding 2089 function with 'w' which operates on a particular window. 2090 The above functions operate on stdscr.</p> 2091 </div> 2092 2093 <div class="SECT2"> 2094 <hr> 2095 2096 <h3 class="SECT2"><a name="CHGAT" id="CHGAT">8.6. chgat() 2097 functions</a></h3> 2098 2099 <p>The function chgat() is listed in the end of the man 2100 page curs_attr. It actually is a useful one. This function 2101 can be used to set attributes for a group of characters 2102 without moving. I mean it !!! without moving the cursor :-) 2103 It changes the attributes of a given number of characters 2104 starting at the current cursor location.</p> 2105 2106 <p>We can give -1 as the character count to update till end 2107 of line. If you want to change attributes of characters 2108 from current position to end of line, just use this.</p> 2109 2110 <pre class= 2111 "PROGRAMLISTING"> chgat(-1, A_REVERSE, 0, NULL);</pre> 2112 <p>This function is useful when changing attributes for 2113 characters that are already on the screen. Move to the 2114 character from which you want to change and change the 2115 attribute.</p> 2116 2117 <p>Other functions wchgat(), mvchgat(), wchgat() behave 2118 similarly except that the w functions operate on the 2119 particular window. The mv functions first move the cursor 2120 then perform the work given to them. Actually chgat is a 2121 macro which is replaced by a wchgat() with stdscr as the 2122 window. Most of the "w-less" functions are macros.</p> 2123 2124 <div class="EXAMPLE"> 2125 <a name="BWICH" id="BWICH"></a> 2126 <p><b>Example 6. Chgat() Usage example</b> 2127 </p> 2128 2129 <pre class="PROGRAMLISTING"><span class= 2130 "INLINEMEDIAOBJECT">#include <curses.h> 2131 2132int main(int argc, char *argv[]) 2133{ initscr(); /* Start curses mode */ 2134 start_color(); /* Start color functionality */ 2135 2136 init_pair(1, COLOR_CYAN, COLOR_BLACK); 2137 printw("A Big string which i didn't care to type fully "); 2138 mvchgat(0, 0, -1, A_BLINK, 1, NULL); 2139 /* 2140 * First two parameters specify the position at which to start 2141 * Third parameter number of characters to update. -1 means till 2142 * end of line 2143 * Forth parameter is the normal attribute you wanted to give 2144 * to the character 2145 * Fifth is the color index. It is the index given during init_pair() 2146 * use 0 if you didn't want color 2147 * Sixth one is always NULL 2148 */ 2149 refresh(); 2150 getch(); 2151 endwin(); /* End curses mode */ 2152 return 0; 2153}</span></pre> 2154 </div> 2155 2156 <p>This example also introduces us to the color world of 2157 curses. Colors will be explained in detail later. Use 0 for 2158 no color.</p> 2159 </div> 2160 </div> 2161 2162 <div class="SECT1"> 2163 <hr> 2164 2165 <h2 class="SECT1"><a name="WINDOWS" id="WINDOWS">9. 2166 Windows</a></h2> 2167 2168 <p>Windows form the most important concept in curses. You 2169 have seen the standard window stdscr above where all the 2170 functions implicitly operated on this window. Now to make 2171 design even a simplest GUI, you need to resort to windows. 2172 The main reason you may want to use windows is to manipulate 2173 parts of the screen separately, for better efficiency, by 2174 updating only the windows that need to be changed and for a 2175 better design. I would say the last reason is the most 2176 important in going for windows. You should always strive for 2177 a better and easy-to-manage design in your programs. If you 2178 are writing big, complex GUIs this is of pivotal importance 2179 before you start doing anything.</p> 2180 2181 <div class="SECT2"> 2182 <hr> 2183 2184 <h3 class="SECT2"><a name="WINDOWBASICS" id= 2185 "WINDOWBASICS">9.1. The basics</a></h3> 2186 2187 <p>A Window can be created by calling the function 2188 <tt class="LITERAL">newwin()</tt>. It doesn't create any 2189 thing on the screen actually. It allocates memory for a 2190 structure to manipulate the window and updates the 2191 structure with data regarding the window such as its size, 2192 beginy, beginx, etc. Hence in curses, a window is just an 2193 abstraction of an imaginary window, which can be 2194 manipulated independent of other parts of screen. The 2195 function newwin() returns a pointer to structure WINDOW, 2196 which can be passed to window related functions such as 2197 wprintw(), etc. Finally the window can be destroyed with 2198 delwin(). It will deallocate the memory associated with the 2199 window structure.</p> 2200 </div> 2201 2202 <div class="SECT2"> 2203 <hr> 2204 2205 <h3 class="SECT2"><a name="LETBEWINDOW" id= 2206 "LETBEWINDOW">9.2. Let there be a Window !!!</a></h3> 2207 2208 <p>What fun is it, if a window is created and we can't see 2209 it. So the fun part begins by displaying the window. The 2210 function <tt class="LITERAL">box()</tt> can be used to draw 2211 a border around the window. Let's explore these functions 2212 in more detail in this example.</p> 2213 2214 <div class="EXAMPLE"> 2215 <a name="BWIBO" id="BWIBO"></a> 2216 <p><b>Example 7. Window Border example</b> 2217 </p> 2218 2219 <pre class="PROGRAMLISTING"><span class= 2220 "INLINEMEDIAOBJECT">#include <curses.h> 2221 2222WINDOW *create_newwin(int height, int width, int starty, int startx); 2223void destroy_win(WINDOW *local_win); 2224 2225int main(int argc, char *argv[]) 2226{ WINDOW *my_win; 2227 int startx, starty, width, height; 2228 int ch; 2229 2230 initscr(); /* Start curses mode */ 2231 cbreak(); /* Line buffering disabled, Pass on 2232 * everty thing to me */ 2233 keypad(stdscr, TRUE); /* I need that nifty F1 */ 2234 2235 height = 3; 2236 width = 10; 2237 starty = (LINES - height) / 2; /* Calculating for a center placement */ 2238 startx = (COLS - width) / 2; /* of the window */ 2239 printw("Press F1 to exit"); 2240 refresh(); 2241 my_win = create_newwin(height, width, starty, startx); 2242 2243 while((ch = getch()) != KEY_F(1)) 2244 { switch(ch) 2245 { case KEY_LEFT: 2246 destroy_win(my_win); 2247 my_win = create_newwin(height, width, starty,--startx); 2248 break; 2249 case KEY_RIGHT: 2250 destroy_win(my_win); 2251 my_win = create_newwin(height, width, starty,++startx); 2252 break; 2253 case KEY_UP: 2254 destroy_win(my_win); 2255 my_win = create_newwin(height, width, --starty,startx); 2256 break; 2257 case KEY_DOWN: 2258 destroy_win(my_win); 2259 my_win = create_newwin(height, width, ++starty,startx); 2260 break; 2261 } 2262 } 2263 2264 endwin(); /* End curses mode */ 2265 return 0; 2266} 2267 2268WINDOW *create_newwin(int height, int width, int starty, int startx) 2269{ WINDOW *local_win; 2270 2271 local_win = newwin(height, width, starty, startx); 2272 box(local_win, 0 , 0); /* 0, 0 gives default characters 2273 * for the vertical and horizontal 2274 * lines */ 2275 wrefresh(local_win); /* Show that box */ 2276 2277 return local_win; 2278} 2279 2280void destroy_win(WINDOW *local_win) 2281{ 2282 /* box(local_win, ' ', ' '); : This won't produce the desired 2283 * result of erasing the window. It will leave its four corners 2284 * and so an ugly remnant of window. 2285 */ 2286 wborder(local_win, ' ', ' ', ' ',' ',' ',' ',' ',' '); 2287 /* The parameters taken are 2288 * 1. win: the window on which to operate 2289 * 2. ls: character to be used for the left side of the window 2290 * 3. rs: character to be used for the right side of the window 2291 * 4. ts: character to be used for the top side of the window 2292 * 5. bs: character to be used for the bottom side of the window 2293 * 6. tl: character to be used for the top left corner of the window 2294 * 7. tr: character to be used for the top right corner of the window 2295 * 8. bl: character to be used for the bottom left corner of the window 2296 * 9. br: character to be used for the bottom right corner of the window 2297 */ 2298 wrefresh(local_win); 2299 delwin(local_win); 2300}</span></pre> 2301 </div> 2302 </div> 2303 2304 <div class="SECT2"> 2305 <hr> 2306 2307 <h3 class="SECT2"><a name="BORDEREXEXPL" id= 2308 "BORDEREXEXPL">9.3. Explanation</a></h3> 2309 2310 <p>Don't scream. I know it is a big example. But I have to 2311 explain some important things here :-). This program 2312 creates a rectangular window that can be moved with left, 2313 right, up, down arrow keys. It repeatedly creates and 2314 destroys windows as user press a key. Don't go beyond the 2315 screen limits. Checking for those limits is left as an 2316 exercise for the reader. Let's dissect it by line by 2317 line.</p> 2318 2319 <p>The <tt class="LITERAL">create_newwin()</tt> function 2320 creates a window with <tt class="LITERAL">newwin()</tt> and 2321 displays a border around it with box. The function 2322 <tt class="LITERAL">destroy_win()</tt> first erases the 2323 window from screen by painting a border with ' ' character 2324 and then calling <tt class="LITERAL">delwin()</tt> to 2325 deallocate memory related to it. Depending on the key the 2326 user presses, starty or startx is changed and a new window 2327 is created.</p> 2328 2329 <p>In the destroy_win, as you can see, I used wborder 2330 instead of box. The reason is written in the comments (You 2331 missed it. I know. Read the code :-)). wborder draws a 2332 border around the window with the characters given to it as 2333 the 4 corner points and the 4 lines. To put it clearly, if 2334 you have called wborder as below:</p> 2335 2336 <pre class= 2337 "PROGRAMLISTING"> wborder(win, '|', '|', '-', '-', '+', '+', '+', '+');</pre> 2338 <p>it produces something like</p> 2339 2340 <pre class="PROGRAMLISTING"> +------------+ 2341 | | 2342 | | 2343 | | 2344 | | 2345 | | 2346 | | 2347 +------------+</pre> 2348 </div> 2349 2350 <div class="SECT2"> 2351 <hr> 2352 2353 <h3 class="SECT2"><a name="OTHERSTUFF" id="OTHERSTUFF">9.4. 2354 The other stuff in the example</a></h3> 2355 2356 <p>You can also see in the above examples, that I have used 2357 the variables COLS, LINES which are initialized to the 2358 screen sizes after initscr(). They can be useful in finding 2359 screen dimensions and finding the center co-ordinate of the 2360 screen as above. The function <tt class= 2361 "LITERAL">getch()</tt> as usual gets the key from keyboard 2362 and according to the key it does the corresponding work. 2363 This type of switch- case is very common in any GUI based 2364 programs.</p> 2365 </div> 2366 2367 <div class="SECT2"> 2368 <hr> 2369 2370 <h3 class="SECT2"><a name="OTHERBORDERFUNCS" id= 2371 "OTHERBORDERFUNCS">9.5. Other Border functions</a></h3> 2372 2373 <p>Above program is grossly inefficient in that with each 2374 press of a key, a window is destroyed and another is 2375 created. So let's write a more efficient program which uses 2376 other border related functions.</p> 2377 2378 <p>The following program uses <tt class= 2379 "LITERAL">mvhline()</tt> and <tt class= 2380 "LITERAL">mvvline()</tt> to achieve similar effect. These 2381 two functions are simple. They create a horizontal or 2382 vertical line of the specified length at the specified 2383 position.</p> 2384 2385 <div class="EXAMPLE"> 2386 <a name="BOTBO" id="BOTBO"></a> 2387 <p><b>Example 8. More border functions</b> 2388 </p> 2389 2390 <pre class="PROGRAMLISTING"><span class= 2391 "INLINEMEDIAOBJECT">#include <curses.h> 2392 2393typedef struct _win_border_struct { 2394 chtype ls, rs, ts, bs, 2395 tl, tr, bl, br; 2396}WIN_BORDER; 2397 2398typedef struct _WIN_struct { 2399 2400 int startx, starty; 2401 int height, width; 2402 WIN_BORDER border; 2403}WIN; 2404 2405void init_win_params(WIN *p_win); 2406void print_win_params(WIN *p_win); 2407void create_box(WIN *win, bool flag); 2408 2409int main(int argc, char *argv[]) 2410{ WIN win; 2411 int ch; 2412 2413 initscr(); /* Start curses mode */ 2414 start_color(); /* Start the color functionality */ 2415 cbreak(); /* Line buffering disabled, Pass on 2416 * everty thing to me */ 2417 keypad(stdscr, TRUE); /* I need that nifty F1 */ 2418 noecho(); 2419 init_pair(1, COLOR_CYAN, COLOR_BLACK); 2420 2421 /* Initialize the window parameters */ 2422 init_win_params(&win); 2423 print_win_params(&win); 2424 2425 attron(COLOR_PAIR(1)); 2426 printw("Press F1 to exit"); 2427 refresh(); 2428 attroff(COLOR_PAIR(1)); 2429 2430 create_box(&win, TRUE); 2431 while((ch = getch()) != KEY_F(1)) 2432 { switch(ch) 2433 { case KEY_LEFT: 2434 create_box(&win, FALSE); 2435 --win.startx; 2436 create_box(&win, TRUE); 2437 break; 2438 case KEY_RIGHT: 2439 create_box(&win, FALSE); 2440 ++win.startx; 2441 create_box(&win, TRUE); 2442 break; 2443 case KEY_UP: 2444 create_box(&win, FALSE); 2445 --win.starty; 2446 create_box(&win, TRUE); 2447 break; 2448 case KEY_DOWN: 2449 create_box(&win, FALSE); 2450 ++win.starty; 2451 create_box(&win, TRUE); 2452 break; 2453 } 2454 } 2455 endwin(); /* End curses mode */ 2456 return 0; 2457} 2458void init_win_params(WIN *p_win) 2459{ 2460 p_win->height = 3; 2461 p_win->width = 10; 2462 p_win->starty = (LINES - p_win->height)/2; 2463 p_win->startx = (COLS - p_win->width)/2; 2464 2465 p_win->border.ls = '|'; 2466 p_win->border.rs = '|'; 2467 p_win->border.ts = '-'; 2468 p_win->border.bs = '-'; 2469 p_win->border.tl = '+'; 2470 p_win->border.tr = '+'; 2471 p_win->border.bl = '+'; 2472 p_win->border.br = '+'; 2473 2474} 2475void print_win_params(WIN *p_win) 2476{ 2477#ifdef _DEBUG 2478 mvprintw(25, 0, "%d %d %d %d", p_win->startx, p_win->starty, 2479 p_win->width, p_win->height); 2480 refresh(); 2481#endif 2482} 2483void create_box(WIN *p_win, bool flag) 2484{ int i, j; 2485 int x, y, w, h; 2486 2487 x = p_win->startx; 2488 y = p_win->starty; 2489 w = p_win->width; 2490 h = p_win->height; 2491 2492 if(flag == TRUE) 2493 { mvaddch(y, x, p_win->border.tl); 2494 mvaddch(y, x + w, p_win->border.tr); 2495 mvaddch(y + h, x, p_win->border.bl); 2496 mvaddch(y + h, x + w, p_win->border.br); 2497 mvhline(y, x + 1, p_win->border.ts, w - 1); 2498 mvhline(y + h, x + 1, p_win->border.bs, w - 1); 2499 mvvline(y + 1, x, p_win->border.ls, h - 1); 2500 mvvline(y + 1, x + w, p_win->border.rs, h - 1); 2501 2502 } 2503 else 2504 for(j = y; j <= y + h; ++j) 2505 for(i = x; i <= x + w; ++i) 2506 mvaddch(j, i, ' '); 2507 2508 refresh(); 2509 2510}</span></pre> 2511 </div> 2512 </div> 2513 </div> 2514 2515 <div class="SECT1"> 2516 <hr> 2517 2518 <h2 class="SECT1"><a name="COLOR" id="COLOR">10. Colors</a></h2> 2519 2520 <div class="SECT2"> 2521 <h3 class="SECT2"><a name="COLORBASICS" id= 2522 "COLORBASICS">10.1. The basics</a></h3> 2523 2524 <p>Life seems dull with no colors. Curses has a nice 2525 mechanism to handle colors. Let's get into the thick of the 2526 things with a small program.</p> 2527 2528 <div class="EXAMPLE"> 2529 <a name="BSICO" id="BSICO"></a> 2530 <p><b>Example 9. A Simple Color example</b> 2531 </p> 2532 2533 <pre class="PROGRAMLISTING"><span class= 2534 "INLINEMEDIAOBJECT">#include <stdlib.h> 2535#include <string.h> 2536#include <curses.h> 2537 2538void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string); 2539int main(int argc, char *argv[]) 2540{ initscr(); /* Start curses mode */ 2541 if(has_colors() == FALSE) 2542 { endwin(); 2543 printf("Your terminal does not support color\n"); 2544 exit(1); 2545 } 2546 start_color(); /* Start color */ 2547 init_pair(1, COLOR_RED, COLOR_BLACK); 2548 2549 attron(COLOR_PAIR(1)); 2550 print_in_middle(stdscr, LINES / 2, 0, 0, "Viola !!! In color ..."); 2551 attroff(COLOR_PAIR(1)); 2552 getch(); 2553 endwin(); 2554} 2555void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string) 2556{ int length, x, y; 2557 float temp; 2558 2559 if(win == NULL) 2560 win = stdscr; 2561 getyx(win, y, x); 2562 if(startx != 0) 2563 x = startx; 2564 if(starty != 0) 2565 y = starty; 2566 if(width == 0) 2567 width = 80; 2568 2569 length = strlen(string); 2570 temp = (width - length)/ 2; 2571 x = startx + (int)temp; 2572 mvwprintw(win, y, x, "%s", string); 2573 refresh(); 2574} 2575</span></pre> 2576 </div> 2577 2578 <p>As you can see, to start using color, you should first 2579 call the function <tt class="LITERAL">start_color()</tt>. 2580 After that, you can use color capabilities of your 2581 terminals using various functions. To find out whether a 2582 terminal has color capabilities or not, you can use 2583 <tt class="LITERAL">has_colors()</tt> function, which 2584 returns FALSE if the terminal does not support color.</p> 2585 2586 <p>Curses initializes all the colors supported by terminal 2587 when start_color() is called. These can be accessed by the 2588 define constants like <tt class="LITERAL">COLOR_BLACK</tt> 2589 , etc. Now to actually start using colors, you have to 2590 define pairs. Colors are always used in pairs. That means 2591 you have to use the function <tt class= 2592 "LITERAL">init_pair()</tt> to define the foreground and 2593 background for the pair number you give. After that that 2594 pair number can be used as a normal attribute with 2595 <tt class="LITERAL">COLOR_PAIR()</tt>function. This may 2596 seem to be cumbersome at first. But this elegant solution 2597 allows us to manage color pairs very easily. To appreciate 2598 it, you have to look into the the source code of "dialog", 2599 a utility for displaying dialog boxes from shell scripts. 2600 The developers have defined foreground and background 2601 combinations for all the colors they might need and 2602 initialized at the beginning. This makes it very easy to 2603 set attributes just by accessing a pair which we already 2604 have defined as a constant.</p> 2605 2606 <p>The following colors are defined in <tt class= 2607 "LITERAL">curses.h</tt>. You can use these as parameters 2608 for various color functions.</p> 2609 2610 <pre class="PROGRAMLISTING"> COLOR_BLACK 0 2611 COLOR_RED 1 2612 COLOR_GREEN 2 2613 COLOR_YELLOW 3 2614 COLOR_BLUE 4 2615 COLOR_MAGENTA 5 2616 COLOR_CYAN 6 2617 COLOR_WHITE 7</pre> 2618 </div> 2619 2620 <div class="SECT2"> 2621 <hr> 2622 2623 <h3 class="SECT2"><a name="CHANGECOLORDEFS" id= 2624 "CHANGECOLORDEFS">10.2. Changing Color Definitions</a></h3> 2625 2626 <p>The function <tt class="LITERAL">init_color()</tt>can be 2627 used to change the rgb values for the colors defined by 2628 curses initially. Say you wanted to lighten the intensity 2629 of red color by a minuscule. Then you can use this function 2630 as</p> 2631 2632 <pre class= 2633 "PROGRAMLISTING"> init_color(COLOR_RED, 700, 0, 0); 2634 /* param 1 : color name 2635 * param 2, 3, 4 : rgb content min = 0, max = 1000 */</pre> 2636 <p>If your terminal cannot change the color definitions, 2637 the function returns ERR. The function <tt class= 2638 "LITERAL">can_change_color()</tt> can be used to find out 2639 whether the terminal has the capability of changing color 2640 content or not. The rgb content is scaled from 0 to 1000. 2641 Initially RED color is defined with content 1000(r), 0(g), 2642 0(b).</p> 2643 </div> 2644 2645 <div class="SECT2"> 2646 <hr> 2647 2648 <h3 class="SECT2"><a name="COLORCONTENT" id= 2649 "COLORCONTENT">10.3. Color Content</a></h3> 2650 2651 <p>The functions <tt class="LITERAL">color_content()</tt> 2652 and <tt class="LITERAL">pair_content()</tt> can be used to 2653 find the color content and foreground, background 2654 combination for the pair.</p> 2655 </div> 2656 </div> 2657 2658 <div class="SECT1"> 2659 <hr> 2660 2661 <h2 class="SECT1"><a name="KEYS" id="KEYS">11. Interfacing 2662 with the key board</a></h2> 2663 2664 <div class="SECT2"> 2665 <h3 class="SECT2"><a name="KEYSBASICS" id= 2666 "KEYSBASICS">11.1. The Basics</a></h3> 2667 2668 <p>No GUI is complete without a strong user interface and 2669 to interact with the user, a curses program should be 2670 sensitive to key presses or the mouse actions done by the 2671 user. Let's deal with the keys first.</p> 2672 2673 <p>As you have seen in almost all of the above examples, it 2674 is very easy to get key input from the user. A simple way 2675 of getting key presses is to use <tt class= 2676 "LITERAL">getch()</tt> function. The cbreak mode should be 2677 enabled to read keys when you are interested in reading 2678 individual key hits rather than complete lines of text 2679 (which usually end with a carriage return). keypad should 2680 be enabled to get the Functions keys, arrow keys, etc. See 2681 the initialization section for details.</p> 2682 2683 <p><tt class="LITERAL">getch()</tt> returns an integer 2684 corresponding to the key pressed. If it is a normal 2685 character, the integer value will be equivalent to the 2686 character. Otherwise it returns a number which can be 2687 matched with the constants defined in <tt class= 2688 "LITERAL">curses.h</tt>. For example if the user presses 2689 F1, the integer returned is 265. This can be checked using 2690 the macro KEY_F() defined in curses.h. This makes reading 2691 keys portable and easy to manage.</p> 2692 2693 <p>For example, if you call getch() like this</p> 2694 2695 <pre class="PROGRAMLISTING"> int ch; 2696 2697 ch = getch();</pre> 2698 <p>getch() will wait for the user to press a key, (unless 2699 you specified a timeout) and when user presses a key, the 2700 corresponding integer is returned. Then you can check the 2701 value returned with the constants defined in curses.h to 2702 match against the keys you want.</p> 2703 2704 <p>The following code piece will do that job.</p> 2705 2706 <pre class="PROGRAMLISTING"> if(ch == KEY_LEFT) 2707 printw("Left arrow is pressed\n");</pre> 2708 <p>Let's write a small program which creates a menu which 2709 can be navigated by up and down arrows.</p> 2710 </div> 2711 2712 <div class="SECT2"> 2713 <hr> 2714 2715 <h3 class="SECT2"><a name="SIMPLEKEYEX" id= 2716 "SIMPLEKEYEX">11.2. A Simple Key Usage example</a></h3> 2717 2718 <div class="EXAMPLE"> 2719 <a name="BSIKE" id="BSIKE"></a> 2720 <p><b>Example 10. A Simple Key Usage example</b> 2721 </p> 2722 2723 <pre class="PROGRAMLISTING"><span class= 2724 "INLINEMEDIAOBJECT">#include <curses.h> 2725 2726#define WIDTH 30 2727#define HEIGHT 10 2728 2729int startx = 0; 2730int starty = 0; 2731 2732char *choices[] = { 2733 "Choice 1", 2734 "Choice 2", 2735 "Choice 3", 2736 "Choice 4", 2737 "Exit", 2738 }; 2739int n_choices = sizeof(choices) / sizeof(char *); 2740void print_menu(WINDOW *menu_win, int highlight); 2741 2742int main() 2743{ WINDOW *menu_win; 2744 int highlight = 1; 2745 int choice = 0; 2746 int c; 2747 2748 initscr(); 2749 clear(); 2750 noecho(); 2751 cbreak(); /* Line buffering disabled. pass on everything */ 2752 startx = (80 - WIDTH) / 2; 2753 starty = (24 - HEIGHT) / 2; 2754 2755 menu_win = newwin(HEIGHT, WIDTH, starty, startx); 2756 keypad(menu_win, TRUE); 2757 mvprintw(0, 0, "Use arrow keys to go up and down, Press enter to select a choice"); 2758 refresh(); 2759 print_menu(menu_win, highlight); 2760 while(1) 2761 { c = wgetch(menu_win); 2762 switch(c) 2763 { case KEY_UP: 2764 if(highlight == 1) 2765 highlight = n_choices; 2766 else 2767 --highlight; 2768 break; 2769 case KEY_DOWN: 2770 if(highlight == n_choices) 2771 highlight = 1; 2772 else 2773 ++highlight; 2774 break; 2775 case 10: 2776 choice = highlight; 2777 break; 2778 default: 2779 mvprintw(24, 0, "Character pressed is = %3d Hopefully it can be printed as '%c'", c, c); 2780 refresh(); 2781 break; 2782 } 2783 print_menu(menu_win, highlight); 2784 if(choice != 0) /* User did a choice come out of the infinite loop */ 2785 break; 2786 } 2787 mvprintw(23, 0, "You chose choice %d with choice string %s\n", choice, choices[choice - 1]); 2788 clrtoeol(); 2789 refresh(); 2790 endwin(); 2791 return 0; 2792} 2793 2794void print_menu(WINDOW *menu_win, int highlight) 2795{ 2796 int x, y, i; 2797 2798 x = 2; 2799 y = 2; 2800 box(menu_win, 0, 0); 2801 for(i = 0; i < n_choices; ++i) 2802 { if(highlight == i + 1) /* High light the present choice */ 2803 { wattron(menu_win, A_REVERSE); 2804 mvwprintw(menu_win, y, x, "%s", choices[i]); 2805 wattroff(menu_win, A_REVERSE); 2806 } 2807 else 2808 mvwprintw(menu_win, y, x, "%s", choices[i]); 2809 ++y; 2810 } 2811 wrefresh(menu_win); 2812} 2813</span></pre> 2814 </div> 2815 </div> 2816 </div> 2817 2818 <div class="SECT1"> 2819 <hr> 2820 2821 <h2 class="SECT1"><a name="MOUSE" id="MOUSE">12. Interfacing 2822 with the mouse</a></h2> 2823 2824 <p>Now that you have seen how to get keys, lets do the same 2825 thing from mouse. Usually each UI allows the user to interact 2826 with both keyboard and mouse.</p> 2827 2828 <div class="SECT2"> 2829 <hr> 2830 2831 <h3 class="SECT2"><a name="MOUSEBASICS" id= 2832 "MOUSEBASICS">12.1. The Basics</a></h3> 2833 2834 <p>Before you do any thing else, the events you want to 2835 receive have to be enabled with <tt class= 2836 "LITERAL">mousemask()</tt>.</p> 2837 2838 <pre class= 2839 "PROGRAMLISTING"> mousemask( mmask_t newmask, /* The events you want to listen to */ 2840 mmask_t *oldmask) /* The old events mask */</pre> 2841 <p>The first parameter to above function is a bit mask of 2842 events you would like to listen. By default, all the events 2843 are turned off. The bit mask <tt class= 2844 "LITERAL">ALL_MOUSE_EVENTS</tt> can be used to get all the 2845 events.</p> 2846 2847 <p>The following are all the event masks:</p> 2848 2849 <pre class="PROGRAMLISTING"> Name Description 2850 --------------------------------------------------------------------- 2851 BUTTON1_PRESSED mouse button 1 down 2852 BUTTON1_RELEASED mouse button 1 up 2853 BUTTON1_CLICKED mouse button 1 clicked 2854 BUTTON1_DOUBLE_CLICKED mouse button 1 double clicked 2855 BUTTON1_TRIPLE_CLICKED mouse button 1 triple clicked 2856 BUTTON2_PRESSED mouse button 2 down 2857 BUTTON2_RELEASED mouse button 2 up 2858 BUTTON2_CLICKED mouse button 2 clicked 2859 BUTTON2_DOUBLE_CLICKED mouse button 2 double clicked 2860 BUTTON2_TRIPLE_CLICKED mouse button 2 triple clicked 2861 BUTTON3_PRESSED mouse button 3 down 2862 BUTTON3_RELEASED mouse button 3 up 2863 BUTTON3_CLICKED mouse button 3 clicked 2864 BUTTON3_DOUBLE_CLICKED mouse button 3 double clicked 2865 BUTTON3_TRIPLE_CLICKED mouse button 3 triple clicked 2866 BUTTON4_PRESSED mouse button 4 down 2867 BUTTON4_RELEASED mouse button 4 up 2868 BUTTON4_CLICKED mouse button 4 clicked 2869 BUTTON4_DOUBLE_CLICKED mouse button 4 double clicked 2870 BUTTON4_TRIPLE_CLICKED mouse button 4 triple clicked 2871 BUTTON_SHIFT shift was down during button state change 2872 BUTTON_CTRL control was down during button state change 2873 BUTTON_ALT alt was down during button state change 2874 ALL_MOUSE_EVENTS report all button state changes 2875 REPORT_MOUSE_POSITION report mouse movement</pre> 2876 </div> 2877 2878 <div class="SECT2"> 2879 <hr> 2880 2881 <h3 class="SECT2"><a name="GETTINGEVENTS" id= 2882 "GETTINGEVENTS">12.2. Getting the events</a></h3> 2883 2884 <p>Once a class of mouse events have been enabled, getch() 2885 class of functions return KEY_MOUSE every time some mouse 2886 event happens. Then the mouse event can be retrieved with 2887 <tt class="LITERAL">getmouse()</tt>.</p> 2888 2889 <p>The code approximately looks like this:</p> 2890 2891 <pre class="PROGRAMLISTING"> MEVENT event; 2892 2893 ch = getch(); 2894 if(ch == KEY_MOUSE) 2895 if(getmouse(&event) == OK) 2896 . /* Do some thing with the event */ 2897 . 2898 .</pre> 2899 <p>getmouse() returns the event into the pointer given to 2900 it. It is a structure which contains</p> 2901 2902 <pre class="PROGRAMLISTING"> typedef struct 2903 { 2904 short id; /* ID to distinguish multiple devices */ 2905 int x, y, z; /* event coordinates */ 2906 mmask_t bstate; /* button state bits */ 2907 } </pre> 2908 <p>The <tt class="LITERAL">bstate</tt> is the main variable 2909 we are interested in. It tells the button state of the 2910 mouse.</p> 2911 2912 <p>Then with a code snippet like the following, we can find 2913 out what happened.</p> 2914 2915 <pre class= 2916 "PROGRAMLISTING"> if(event.bstate & BUTTON1_PRESSED) 2917 printw("Left Button Pressed");</pre> 2918 </div> 2919 2920 <div class="SECT2"> 2921 <hr> 2922 2923 <h3 class="SECT2"><a name="MOUSETOGETHER" id= 2924 "MOUSETOGETHER">12.3. Putting it all Together</a></h3> 2925 2926 <p>That's pretty much interfacing with mouse. Let's create 2927 the same menu and enable mouse interaction. To make things 2928 simpler, key handling is removed.</p> 2929 2930 <div class="EXAMPLE"> 2931 <a name="BMOME" id="BMOME"></a> 2932 <p><b>Example 11. Access the menu with mouse !!!</b> 2933 </p> 2934 2935 <pre class="PROGRAMLISTING"><span class= 2936 "INLINEMEDIAOBJECT">#include <string.h> 2937#include <curses.h> 2938 2939#define WIDTH 30 2940#define HEIGHT 10 2941 2942int startx = 0; 2943int starty = 0; 2944 2945char *choices[] = { "Choice 1", 2946 "Choice 2", 2947 "Choice 3", 2948 "Choice 4", 2949 "Exit", 2950 }; 2951 2952int n_choices = sizeof(choices) / sizeof(char *); 2953 2954void print_menu(WINDOW *menu_win, int highlight); 2955void report_choice(int mouse_x, int mouse_y, int *p_choice); 2956 2957int main() 2958{ int c, choice = 0; 2959 WINDOW *menu_win; 2960 MEVENT event; 2961 2962 /* Initialize curses */ 2963 initscr(); 2964 clear(); 2965 noecho(); 2966 cbreak(); //Line buffering disabled. pass on everything 2967 2968 /* Try to put the window in the middle of screen */ 2969 startx = (80 - WIDTH) / 2; 2970 starty = (24 - HEIGHT) / 2; 2971 2972 attron(A_REVERSE); 2973 mvprintw(23, 1, "Click on Exit to quit (Works best in a virtual console)"); 2974 refresh(); 2975 attroff(A_REVERSE); 2976 2977 /* Print the menu for the first time */ 2978 menu_win = newwin(HEIGHT, WIDTH, starty, startx); 2979 keypad(menu_win, TRUE); 2980 print_menu(menu_win, 1); 2981 /* Get all the mouse events */ 2982 mousemask(ALL_MOUSE_EVENTS, NULL); 2983 2984 while(1) 2985 { c = wgetch(menu_win); 2986 switch(c) 2987 { case KEY_MOUSE: 2988 if(getmouse(&event) == OK) 2989 { /* When the user clicks left mouse button */ 2990 if(event.bstate & BUTTON1_PRESSED) 2991 { report_choice(event.x + 1, event.y + 1, &choice); 2992 if(choice == -1) //Exit chosen 2993 goto end; 2994 mvprintw(22, 1, "Choice made is : %d String Chosen is \"%10s\"", choice, choices[choice - 1]); 2995 refresh(); 2996 } 2997 } 2998 print_menu(menu_win, choice); 2999 break; 3000 } 3001 } 3002end: 3003 endwin(); 3004 return 0; 3005} 3006 3007void print_menu(WINDOW *menu_win, int highlight) 3008{ 3009 int x, y, i; 3010 3011 x = 2; 3012 y = 2; 3013 box(menu_win, 0, 0); 3014 for(i = 0; i < n_choices; ++i) 3015 { if(highlight == i + 1) 3016 { wattron(menu_win, A_REVERSE); 3017 mvwprintw(menu_win, y, x, "%s", choices[i]); 3018 wattroff(menu_win, A_REVERSE); 3019 } 3020 else 3021 mvwprintw(menu_win, y, x, "%s", choices[i]); 3022 ++y; 3023 } 3024 wrefresh(menu_win); 3025} 3026 3027/* Report the choice according to mouse position */ 3028void report_choice(int mouse_x, int mouse_y, int *p_choice) 3029{ int i,j, choice; 3030 3031 i = startx + 2; 3032 j = starty + 3; 3033 3034 for(choice = 0; choice < n_choices; ++choice) 3035 if(mouse_y == j + choice && mouse_x >= i && mouse_x <= i + strlen(choices[choice])) 3036 { if(choice == n_choices - 1) 3037 *p_choice = -1; 3038 else 3039 *p_choice = choice + 1; 3040 break; 3041 } 3042}</span></pre> 3043 </div> 3044 </div> 3045 3046 <div class="SECT2"> 3047 <hr> 3048 3049 <h3 class="SECT2"><a name="MISCMOUSEFUNCS" id= 3050 "MISCMOUSEFUNCS">12.4. Miscellaneous Functions</a></h3> 3051 3052 <p>The functions mouse_trafo() and wmouse_trafo() can be 3053 used to convert to mouse co-ordinates to screen relative 3054 co-ordinates. See curs_mouse(3X) man page for details.</p> 3055 3056 <p>The mouseinterval function sets the maximum time (in 3057 thousands of a second) that can elapse between press and 3058 release events in order for them to be recognized as a 3059 click. This function returns the previous interval value. 3060 The default is one fifth of a second.</p> 3061 </div> 3062 </div> 3063 3064 <div class="SECT1"> 3065 <hr> 3066 3067 <h2 class="SECT1"><a name="SCREEN" id="SCREEN">13. Screen 3068 Manipulation</a></h2> 3069 3070 <p>In this section, we will look into some functions, which 3071 allow us to manage the screen efficiently and to write some 3072 fancy programs. This is especially important in writing 3073 games.</p> 3074 3075 <div class="SECT2"> 3076 <hr> 3077 3078 <h3 class="SECT2"><a name="GETYX" id="GETYX">13.1. getyx() 3079 functions</a></h3> 3080 3081 <p>The function <tt class="LITERAL">getyx()</tt> can be 3082 used to find out the present cursor co-ordinates. It will 3083 fill the values of x and y co-ordinates in the arguments 3084 given to it. Since getyx() is a macro you don't have to 3085 pass the address of the variables. It can be called as</p> 3086 3087 <pre class="PROGRAMLISTING"> getyx(win, y, x); 3088 /* win: window pointer 3089 * y, x: y, x co-ordinates will be put into this variables 3090 */</pre> 3091 <p>The function getparyx() gets the beginning co-ordinates 3092 of the sub window relative to the main window. This is some 3093 times useful to update a sub window. When designing fancy 3094 stuff like writing multiple menus, it becomes difficult to 3095 store the menu positions, their first option co-ordinates, 3096 etc. A simple solution to this problem, is to create menus 3097 in sub windows and later find the starting co-ordinates of 3098 the menus by using getparyx().</p> 3099 3100 <p>The functions getbegyx() and getmaxyx() store current 3101 window's beginning and maximum co-ordinates. These 3102 functions are useful in the same way as above in managing 3103 the windows and sub windows effectively.</p> 3104 </div> 3105 3106 <div class="SECT2"> 3107 <hr> 3108 3109 <h3 class="SECT2"><a name="SCREENDUMP" id= 3110 "SCREENDUMP">13.2. Screen Dumping</a></h3> 3111 3112 <p>While writing games, some times it becomes necessary to 3113 store the state of the screen and restore it back to the 3114 same state. The function scr_dump() can be used to dump the 3115 screen contents to a file given as an argument. Later it 3116 can be restored by scr_restore function. These two simple 3117 functions can be used effectively to maintain a fast moving 3118 game with changing scenarios.</p> 3119 </div> 3120 3121 <div class="SECT2"> 3122 <hr> 3123 3124 <h3 class="SECT2"><a name="WINDOWDUMP" id= 3125 "WINDOWDUMP">13.3. Window Dumping</a></h3> 3126 3127 <p>To store and restore windows, the functions <tt class= 3128 "LITERAL">putwin()</tt> and <tt class= 3129 "LITERAL">getwin()</tt> can be used. <tt class= 3130 "LITERAL">putwin()</tt> puts the present window state into 3131 a file, which can be later restored by <tt class= 3132 "LITERAL">getwin()</tt>.</p> 3133 3134 <p>The function <tt class="LITERAL">copywin()</tt> can be 3135 used to copy a window completely onto another window. It 3136 takes the source and destination windows as parameters and 3137 according to the rectangle specified, it copies the 3138 rectangular region from source to destination window. Its 3139 last parameter specifies whether to overwrite or just 3140 overlay the contents on to the destination window. If this 3141 argument is true, then the copying is non-destructive.</p> 3142 </div> 3143 </div> 3144 3145 <div class="SECT1"> 3146 <hr> 3147 3148 <h2 class="SECT1"><a name="MISC" id="MISC">14. Miscellaneous 3149 features</a></h2> 3150 3151 <p>Now you know enough features to write a good curses 3152 program, with all bells and whistles. There are some 3153 miscellaneous functions which are useful in various cases. 3154 Let's go headlong into some of those.</p> 3155 3156 <div class="SECT2"> 3157 <hr> 3158 3159 <h3 class="SECT2"><a name="CURSSET" id="CURSSET">14.1. 3160 curs_set()</a></h3> 3161 3162 <p>This function can be used to make the cursor invisible. 3163 The parameter to this function should be</p> 3164 3165 <pre class="PROGRAMLISTING"> 0 : invisible or 3166 1 : normal or 3167 2 : very visible.</pre> 3168 </div> 3169 3170 <div class="SECT2"> 3171 <hr> 3172 3173 <h3 class="SECT2"><a name="TEMPLEAVE" id="TEMPLEAVE">14.2. 3174 Temporarily Leaving Curses mode</a></h3> 3175 3176 <p>Some times you may want to get back to cooked mode 3177 (normal line buffering mode) temporarily. In such a case 3178 you will first need to save the tty modes with a call to 3179 <tt class="LITERAL">def_prog_mode()</tt> and then call 3180 <tt class="LITERAL">endwin()</tt> to end the curses mode. 3181 This will leave you in the original tty mode. To get back 3182 to curses once you are done, call <tt class= 3183 "LITERAL">reset_prog_mode()</tt> . This function returns 3184 the tty to the state stored by <tt class= 3185 "LITERAL">def_prog_mode()</tt>. Then do refresh(), and you 3186 are back to the curses mode. Here is an example showing the 3187 sequence of things to be done.</p> 3188 3189 <div class="EXAMPLE"> 3190 <a name="BTELE" id="BTELE"></a> 3191 <p><b>Example 12. Temporarily Leaving Curses Mode</b> 3192 </p> 3193 3194 <pre class="PROGRAMLISTING"><span class= 3195 "INLINEMEDIAOBJECT">#include <stdlib.h> 3196#include <curses.h> 3197 3198int main() 3199{ 3200 initscr(); /* Start curses mode */ 3201 printw("Hello World !!!\n"); /* Print Hello World */ 3202 refresh(); /* Print it on to the real screen */ 3203 def_prog_mode(); /* Save the tty modes */ 3204 endwin(); /* End curses mode temporarily */ 3205 system("/bin/sh"); /* Do whatever you like in cooked mode */ 3206 reset_prog_mode(); /* Return to the previous tty mode*/ 3207 /* stored by def_prog_mode() */ 3208 refresh(); /* Do refresh() to restore the */ 3209 /* Screen contents */ 3210 printw("Another String\n"); /* Back to curses use the full */ 3211 refresh(); /* capabilities of curses */ 3212 endwin(); /* End curses mode */ 3213 3214 return 0; 3215}</span></pre> 3216 </div> 3217 </div> 3218 3219 <div class="SECT2"> 3220 <hr> 3221 3222 <h3 class="SECT2"><a name="ACSVARS" id="ACSVARS">14.3. ACS_ 3223 variables</a></h3> 3224 3225 <p>If you have ever programmed in DOS, you know about those 3226 nifty characters in extended character set. They are 3227 printable only on some terminals. NCURSES functions like 3228 <tt class="LITERAL">box()</tt> use these characters. All 3229 these variables start with ACS meaning alternative 3230 character set. You might have noticed me using these 3231 characters in some of the programs above. Here is an 3232 example showing all the characters.</p> 3233 3234 <div class="EXAMPLE"> 3235 <a name="BACSVARS" id="BACSVARS"></a> 3236 <p><b>Example 13. ACS Variables Example</b> 3237 </p> 3238 3239 <pre class="PROGRAMLISTING"><span class= 3240 "INLINEMEDIAOBJECT">#include <curses.h> 3241 3242int main() 3243{ 3244 initscr(); 3245 3246 printw("Upper left corner "); addch(ACS_ULCORNER); printw("\n"); 3247 printw("Lower left corner "); addch(ACS_LLCORNER); printw("\n"); 3248 printw("Lower right corner "); addch(ACS_LRCORNER); printw("\n"); 3249 printw("Tee pointing right "); addch(ACS_LTEE); printw("\n"); 3250 printw("Tee pointing left "); addch(ACS_RTEE); printw("\n"); 3251 printw("Tee pointing up "); addch(ACS_BTEE); printw("\n"); 3252 printw("Tee pointing down "); addch(ACS_TTEE); printw("\n"); 3253 printw("Horizontal line "); addch(ACS_HLINE); printw("\n"); 3254 printw("Vertical line "); addch(ACS_VLINE); printw("\n"); 3255 printw("Large Plus or cross over "); addch(ACS_PLUS); printw("\n"); 3256 printw("Scan Line 1 "); addch(ACS_S1); printw("\n"); 3257 printw("Scan Line 3 "); addch(ACS_S3); printw("\n"); 3258 printw("Scan Line 7 "); addch(ACS_S7); printw("\n"); 3259 printw("Scan Line 9 "); addch(ACS_S9); printw("\n"); 3260 printw("Diamond "); addch(ACS_DIAMOND); printw("\n"); 3261 printw("Checker board (stipple) "); addch(ACS_CKBOARD); printw("\n"); 3262 printw("Degree Symbol "); addch(ACS_DEGREE); printw("\n"); 3263 printw("Plus/Minus Symbol "); addch(ACS_PLMINUS); printw("\n"); 3264 printw("Bullet "); addch(ACS_BULLET); printw("\n"); 3265 printw("Arrow Pointing Left "); addch(ACS_LARROW); printw("\n"); 3266 printw("Arrow Pointing Right "); addch(ACS_RARROW); printw("\n"); 3267 printw("Arrow Pointing Down "); addch(ACS_DARROW); printw("\n"); 3268 printw("Arrow Pointing Up "); addch(ACS_UARROW); printw("\n"); 3269 printw("Board of squares "); addch(ACS_BOARD); printw("\n"); 3270 printw("Lantern Symbol "); addch(ACS_LANTERN); printw("\n"); 3271 printw("Solid Square Block "); addch(ACS_BLOCK); printw("\n"); 3272 printw("Less/Equal sign "); addch(ACS_LEQUAL); printw("\n"); 3273 printw("Greater/Equal sign "); addch(ACS_GEQUAL); printw("\n"); 3274 printw("Pi "); addch(ACS_PI); printw("\n"); 3275 printw("Not equal "); addch(ACS_NEQUAL); printw("\n"); 3276 printw("UK pound sign "); addch(ACS_STERLING); printw("\n"); 3277 3278 refresh(); 3279 getch(); 3280 endwin(); 3281 3282 return 0; 3283}</span></pre> 3284 </div> 3285 </div> 3286 </div> 3287 3288 <div class="SECT1"> 3289 <hr> 3290 3291 <h2 class="SECT1"><a name="OTHERLIB" id="OTHERLIB">15. Other 3292 libraries</a></h2> 3293 3294 <p>Apart from the curses library, there are few text mode 3295 libraries, which provide more functionality and a lot of 3296 features. The following sections explain three standard 3297 libraries which are usually distributed along with 3298 curses.</p> 3299 </div> 3300 3301 <div class="SECT1"> 3302 <hr> 3303 3304 <h2 class="SECT1"><a name="PANELS" id="PANELS">16. Panel 3305 Library</a></h2> 3306 3307 <p>Now that you are proficient in curses, you wanted to do 3308 some thing big. You created a lot of overlapping windows to 3309 give a professional windows-type look. Unfortunately, it soon 3310 becomes difficult to manage these. The multiple refreshes, 3311 updates plunge you into a nightmare. The overlapping windows 3312 create blotches, whenever you forget to refresh the windows 3313 in the proper order.</p> 3314 3315 <p>Don't despair. There is an elegant solution provided in 3316 panels library. In the words of developers of ncurses</p> 3317 3318 <p><span class="emphasis"><i class="EMPHASIS">When your 3319 interface design is such that windows may dive deeper into 3320 the visibility stack or pop to the top at runtime, the 3321 resulting book-keeping can be tedious and difficult to get 3322 right. Hence the panels library.</i></span> 3323 </p> 3324 3325 <p>If you have lot of overlapping windows, then panels 3326 library is the way to go. It obviates the need of doing 3327 series of wnoutrefresh(), doupdate() and relieves the burden 3328 of doing it correctly(bottom up). The library maintains 3329 information about the order of windows, their overlapping and 3330 update the screen properly. So why wait? Let's take a close 3331 peek into panels.</p> 3332 3333 <div class="SECT2"> 3334 <hr> 3335 3336 <h3 class="SECT2"><a name="PANELBASICS" id= 3337 "PANELBASICS">16.1. The Basics</a></h3> 3338 3339 <p>Panel object is a window that is implicitly treated as 3340 part of a deck including all other panel objects. The deck 3341 is treated as a stack with the top panel being completely 3342 visible and the other panels may or may not be obscured 3343 according to their positions. So the basic idea is to 3344 create a stack of overlapping panels and use panels library 3345 to display them correctly. There is a function similar to 3346 refresh() which, when called , displays panels in the 3347 correct order. Functions are provided to hide or show 3348 panels, move panels, change its size, etc. The overlapping 3349 problem is managed by the panels library during all the 3350 calls to these functions.</p> 3351 3352 <p>The general flow of a panel program goes like this:</p> 3353 3354 <ol type="1"> 3355 <li> 3356 <p>Create the windows (with newwin()) to be attached to 3357 the panels.</p> 3358 </li> 3359 3360 <li> 3361 <p>Create panels with the chosen visibility order. 3362 Stack them up according to the desired visibility. The 3363 function new_panel() is used to created panels.</p> 3364 </li> 3365 3366 <li> 3367 <p>Call update_panels() to write the panels to the 3368 virtual screen in correct visibility order. Do a 3369 doupdate() to show it on the screen.</p> 3370 </li> 3371 3372 <li> 3373 <p>Mainpulate the panels with show_panel(), 3374 hide_panel(), move_panel(), etc. Make use of helper 3375 functions like panel_hidden() and panel_window(). Make 3376 use of user pointer to store custom data for a panel. 3377 Use the functions set_panel_userptr() and 3378 panel_userptr() to set and get the user pointer for a 3379 panel.</p> 3380 </li> 3381 3382 <li> 3383 <p>When you are done with the panel use del_panel() to 3384 delete the panel.</p> 3385 </li> 3386 </ol> 3387 3388 <p>Let's make the concepts clear, with some programs. The 3389 following is a simple program which creates 3 overlapping 3390 panels and shows them on the screen.</p> 3391 </div> 3392 3393 <div class="SECT2"> 3394 <hr> 3395 3396 <h3 class="SECT2"><a name="COMPILEPANELS" id= 3397 "COMPILEPANELS">16.2. Compiling With the Panels Library</a></h3> 3398 3399 <p>To use panels library functions, you have to include 3400 panel.h and to link the program with panels library the 3401 flag -lpanel should be added along with -lncurses in that 3402 order.</p> 3403 3404 <pre class="PROGRAMLISTING"> #include <panel.h> 3405 . 3406 . 3407 . 3408 3409 compile and link: gcc <program file> -lpanel -lncurses</pre> 3410 <div class="EXAMPLE"> 3411 <a name="PPASI" id="PPASI"></a> 3412 <p><b>Example 14. Panel basics</b> 3413 </p> 3414 3415 <pre class="PROGRAMLISTING"><span class= 3416 "INLINEMEDIAOBJECT">#include <panel.h> 3417 3418int main() 3419{ WINDOW *my_wins[3]; 3420 PANEL *my_panels[3]; 3421 int lines = 10, cols = 40, y = 2, x = 4, i; 3422 3423 initscr(); 3424 cbreak(); 3425 noecho(); 3426 3427 /* Create windows for the panels */ 3428 my_wins[0] = newwin(lines, cols, y, x); 3429 my_wins[1] = newwin(lines, cols, y + 1, x + 5); 3430 my_wins[2] = newwin(lines, cols, y + 2, x + 10); 3431 3432 /* 3433 * Create borders around the windows so that you can see the effect 3434 * of panels 3435 */ 3436 for(i = 0; i < 3; ++i) 3437 box(my_wins[i], 0, 0); 3438 3439 /* Attach a panel to each window */ /* Order is bottom up */ 3440 my_panels[0] = new_panel(my_wins[0]); /* Push 0, order: stdscr-0 */ 3441 my_panels[1] = new_panel(my_wins[1]); /* Push 1, order: stdscr-0-1 */ 3442 my_panels[2] = new_panel(my_wins[2]); /* Push 2, order: stdscr-0-1-2 */ 3443 3444 /* Update the stacking order. 2nd panel will be on top */ 3445 update_panels(); 3446 3447 /* Show it on the screen */ 3448 doupdate(); 3449 3450 getch(); 3451 endwin(); 3452} 3453</span></pre> 3454 </div> 3455 3456 <p>As you can see, above program follows a simple flow as 3457 explained. The windows are created with newwin() and then 3458 they are attached to panels with new_panel(). As we attach 3459 one panel after another, the stack of panels gets updated. 3460 To put them on screen update_panels() and doupdate() are 3461 called.</p> 3462 </div> 3463 3464 <div class="SECT2"> 3465 <hr> 3466 3467 <h3 class="SECT2"><a name="PANELBROWSING" id= 3468 "PANELBROWSING">16.3. Panel Window Browsing</a></h3> 3469 3470 <p>A slightly complicated example is given below. This 3471 program creates 3 windows which can be cycled through using 3472 tab. Have a look at the code.</p> 3473 3474 <div class="EXAMPLE"> 3475 <a name="PPABR" id="PPABR"></a> 3476 <p><b>Example 15. Panel Window Browsing Example</b> 3477 </p> 3478 3479 <pre class="PROGRAMLISTING"><span class= 3480 "INLINEMEDIAOBJECT">#include <string.h> 3481#include <panel.h> 3482 3483#define NLINES 10 3484#define NCOLS 40 3485 3486void init_wins(WINDOW **wins, int n); 3487void win_show(WINDOW *win, char *label, int label_color); 3488void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color); 3489 3490int main() 3491{ WINDOW *my_wins[3]; 3492 PANEL *my_panels[3]; 3493 PANEL *top; 3494 int ch; 3495 3496 /* Initialize curses */ 3497 initscr(); 3498 start_color(); 3499 cbreak(); 3500 noecho(); 3501 keypad(stdscr, TRUE); 3502 3503 /* Initialize all the colors */ 3504 init_pair(1, COLOR_RED, COLOR_BLACK); 3505 init_pair(2, COLOR_GREEN, COLOR_BLACK); 3506 init_pair(3, COLOR_BLUE, COLOR_BLACK); 3507 init_pair(4, COLOR_CYAN, COLOR_BLACK); 3508 3509 init_wins(my_wins, 3); 3510 3511 /* Attach a panel to each window */ /* Order is bottom up */ 3512 my_panels[0] = new_panel(my_wins[0]); /* Push 0, order: stdscr-0 */ 3513 my_panels[1] = new_panel(my_wins[1]); /* Push 1, order: stdscr-0-1 */ 3514 my_panels[2] = new_panel(my_wins[2]); /* Push 2, order: stdscr-0-1-2 */ 3515 3516 /* Set up the user pointers to the next panel */ 3517 set_panel_userptr(my_panels[0], my_panels[1]); 3518 set_panel_userptr(my_panels[1], my_panels[2]); 3519 set_panel_userptr(my_panels[2], my_panels[0]); 3520 3521 /* Update the stacking order. 2nd panel will be on top */ 3522 update_panels(); 3523 3524 /* Show it on the screen */ 3525 attron(COLOR_PAIR(4)); 3526 mvprintw(LINES - 2, 0, "Use tab to browse through the windows (F1 to Exit)"); 3527 attroff(COLOR_PAIR(4)); 3528 doupdate(); 3529 3530 top = my_panels[2]; 3531 while((ch = getch()) != KEY_F(1)) 3532 { switch(ch) 3533 { case 9: 3534 top = (PANEL *)panel_userptr(top); 3535 top_panel(top); 3536 break; 3537 } 3538 update_panels(); 3539 doupdate(); 3540 } 3541 endwin(); 3542 return 0; 3543} 3544 3545/* Put all the windows */ 3546void init_wins(WINDOW **wins, int n) 3547{ int x, y, i; 3548 char label[80]; 3549 3550 y = 2; 3551 x = 10; 3552 for(i = 0; i < n; ++i) 3553 { wins[i] = newwin(NLINES, NCOLS, y, x); 3554 sprintf(label, "Window Number %d", i + 1); 3555 win_show(wins[i], label, i + 1); 3556 y += 3; 3557 x += 7; 3558 } 3559} 3560 3561/* Show the window with a border and a label */ 3562void win_show(WINDOW *win, char *label, int label_color) 3563{ int startx, starty, height, width; 3564 3565 getbegyx(win, starty, startx); 3566 getmaxyx(win, height, width); 3567 3568 box(win, 0, 0); 3569 mvwaddch(win, 2, 0, ACS_LTEE); 3570 mvwhline(win, 2, 1, ACS_HLINE, width - 2); 3571 mvwaddch(win, 2, width - 1, ACS_RTEE); 3572 3573 print_in_middle(win, 1, 0, width, label, COLOR_PAIR(label_color)); 3574} 3575 3576void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color) 3577{ int length, x, y; 3578 float temp; 3579 3580 if(win == NULL) 3581 win = stdscr; 3582 getyx(win, y, x); 3583 if(startx != 0) 3584 x = startx; 3585 if(starty != 0) 3586 y = starty; 3587 if(width == 0) 3588 width = 80; 3589 3590 length = strlen(string); 3591 temp = (width - length)/ 2; 3592 x = startx + (int)temp; 3593 wattron(win, color); 3594 mvwprintw(win, y, x, "%s", string); 3595 wattroff(win, color); 3596 refresh(); 3597}</span></pre> 3598 </div> 3599 </div> 3600 3601 <div class="SECT2"> 3602 <hr> 3603 3604 <h3 class="SECT2"><a name="USERPTRUSING" id= 3605 "USERPTRUSING">16.4. Using User Pointers</a></h3> 3606 3607 <p>In the above example I used user pointers to find out 3608 the next window in the cycle. We can attach custom 3609 information to the panel by specifying a user pointer, 3610 which can point to any information you want to store. In 3611 this case I stored the pointer to the next panel in the 3612 cycle. User pointer for a panel can be set with the 3613 function <tt class="LITERAL">set_panel_userptr()</tt>. It 3614 can be accessed using the function <tt class= 3615 "LITERAL">panel_userptr()</tt> which will return the user 3616 pointer for the panel given as argument. After finding the 3617 next panel in the cycle, it is brought to the top by the 3618 function top_panel(). This function brings the panel given 3619 as argument to the top of the panel stack.</p> 3620 </div> 3621 3622 <div class="SECT2"> 3623 <hr> 3624 3625 <h3 class="SECT2"><a name="PANELMOVERESIZE" id= 3626 "PANELMOVERESIZE">16.5. Moving and Resizing Panels</a></h3> 3627 3628 <p>The function <tt class="LITERAL">move_panel()</tt> can 3629 be used to move a panel to the desired location. It does 3630 not change the position of the panel in the stack. Make 3631 sure that you use move_panel() instead mvwin() on the 3632 window associated with the panel.</p> 3633 3634 <p>Resizing a panel is slightly complex. There is no 3635 straight forward function just to resize the window 3636 associated with a panel. A solution to resize a panel is to 3637 create a new window with the desired sizes, change the 3638 window associated with the panel using replace_panel(). 3639 Don't forget to delete the old window. The window 3640 associated with a panel can be found by using the function 3641 panel_window().</p> 3642 3643 <p>The following program shows these concepts, in 3644 supposedly simple program. You can cycle through the window 3645 with <TAB> as usual. To resize or move the active 3646 panel press 'r' for resize 'm' for moving. Then use arrow 3647 keys to resize or move it to the desired way and press 3648 enter to end your resizing or moving. This example makes 3649 use of user data to get the required data to do the 3650 operations.</p> 3651 3652 <div class="EXAMPLE"> 3653 <a name="PPARE" id="PPARE"></a> 3654 <p><b>Example 16. Panel Moving and Resizing example</b> 3655 </p> 3656 3657 <pre class="PROGRAMLISTING"><span class= 3658 "INLINEMEDIAOBJECT">#include <stdlib.h> 3659#include <string.h> 3660#include <panel.h> 3661 3662typedef struct _PANEL_DATA { 3663 int x, y, w, h; 3664 char label[80]; 3665 int label_color; 3666 PANEL *next; 3667}PANEL_DATA; 3668 3669#define NLINES 10 3670#define NCOLS 40 3671 3672void init_wins(WINDOW **wins, int n); 3673void win_show(WINDOW *win, char *label, int label_color); 3674void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color); 3675void set_user_ptrs(PANEL **panels, int n); 3676 3677int main() 3678{ WINDOW *my_wins[3]; 3679 PANEL *my_panels[3]; 3680 PANEL_DATA *top; 3681 PANEL *stack_top; 3682 WINDOW *temp_win, *old_win; 3683 int ch; 3684 int newx, newy, neww, newh; 3685 int size = FALSE, move = FALSE; 3686 3687 /* Initialize curses */ 3688 initscr(); 3689 start_color(); 3690 cbreak(); 3691 noecho(); 3692 keypad(stdscr, TRUE); 3693 3694 /* Initialize all the colors */ 3695 init_pair(1, COLOR_RED, COLOR_BLACK); 3696 init_pair(2, COLOR_GREEN, COLOR_BLACK); 3697 init_pair(3, COLOR_BLUE, COLOR_BLACK); 3698 init_pair(4, COLOR_CYAN, COLOR_BLACK); 3699 3700 init_wins(my_wins, 3); 3701 3702 /* Attach a panel to each window */ /* Order is bottom up */ 3703 my_panels[0] = new_panel(my_wins[0]); /* Push 0, order: stdscr-0 */ 3704 my_panels[1] = new_panel(my_wins[1]); /* Push 1, order: stdscr-0-1 */ 3705 my_panels[2] = new_panel(my_wins[2]); /* Push 2, order: stdscr-0-1-2 */ 3706 3707 set_user_ptrs(my_panels, 3); 3708 /* Update the stacking order. 2nd panel will be on top */ 3709 update_panels(); 3710 3711 /* Show it on the screen */ 3712 attron(COLOR_PAIR(4)); 3713 mvprintw(LINES - 3, 0, "Use 'm' for moving, 'r' for resizing"); 3714 mvprintw(LINES - 2, 0, "Use tab to browse through the windows (F1 to Exit)"); 3715 attroff(COLOR_PAIR(4)); 3716 doupdate(); 3717 3718 stack_top = my_panels[2]; 3719 top = (PANEL_DATA *)panel_userptr(stack_top); 3720 newx = top->x; 3721 newy = top->y; 3722 neww = top->w; 3723 newh = top->h; 3724 while((ch = getch()) != KEY_F(1)) 3725 { switch(ch) 3726 { case 9: /* Tab */ 3727 top = (PANEL_DATA *)panel_userptr(stack_top); 3728 top_panel(top->next); 3729 stack_top = top->next; 3730 top = (PANEL_DATA *)panel_userptr(stack_top); 3731 newx = top->x; 3732 newy = top->y; 3733 neww = top->w; 3734 newh = top->h; 3735 break; 3736 case 'r': /* Re-Size*/ 3737 size = TRUE; 3738 attron(COLOR_PAIR(4)); 3739 mvprintw(LINES - 4, 0, "Entered Resizing :Use Arrow Keys to resize and press <ENTER> to end resizing"); 3740 refresh(); 3741 attroff(COLOR_PAIR(4)); 3742 break; 3743 case 'm': /* Move */ 3744 attron(COLOR_PAIR(4)); 3745 mvprintw(LINES - 4, 0, "Entered Moving: Use Arrow Keys to Move and press <ENTER> to end moving"); 3746 refresh(); 3747 attroff(COLOR_PAIR(4)); 3748 move = TRUE; 3749 break; 3750 case KEY_LEFT: 3751 if(size == TRUE) 3752 { --newx; 3753 ++neww; 3754 } 3755 if(move == TRUE) 3756 --newx; 3757 break; 3758 case KEY_RIGHT: 3759 if(size == TRUE) 3760 { ++newx; 3761 --neww; 3762 } 3763 if(move == TRUE) 3764 ++newx; 3765 break; 3766 case KEY_UP: 3767 if(size == TRUE) 3768 { --newy; 3769 ++newh; 3770 } 3771 if(move == TRUE) 3772 --newy; 3773 break; 3774 case KEY_DOWN: 3775 if(size == TRUE) 3776 { ++newy; 3777 --newh; 3778 } 3779 if(move == TRUE) 3780 ++newy; 3781 break; 3782 case 10: /* Enter */ 3783 move(LINES - 4, 0); 3784 clrtoeol(); 3785 refresh(); 3786 if(size == TRUE) 3787 { old_win = panel_window(stack_top); 3788 temp_win = newwin(newh, neww, newy, newx); 3789 replace_panel(stack_top, temp_win); 3790 win_show(temp_win, top->label, top->label_color); 3791 delwin(old_win); 3792 size = FALSE; 3793 } 3794 if(move == TRUE) 3795 { move_panel(stack_top, newy, newx); 3796 move = FALSE; 3797 } 3798 break; 3799 3800 } 3801 attron(COLOR_PAIR(4)); 3802 mvprintw(LINES - 3, 0, "Use 'm' for moving, 'r' for resizing"); 3803 mvprintw(LINES - 2, 0, "Use tab to browse through the windows (F1 to Exit)"); 3804 attroff(COLOR_PAIR(4)); 3805 refresh(); 3806 update_panels(); 3807 doupdate(); 3808 } 3809 endwin(); 3810 return 0; 3811} 3812 3813/* Put all the windows */ 3814void init_wins(WINDOW **wins, int n) 3815{ int x, y, i; 3816 char label[80]; 3817 3818 y = 2; 3819 x = 10; 3820 for(i = 0; i < n; ++i) 3821 { wins[i] = newwin(NLINES, NCOLS, y, x); 3822 sprintf(label, "Window Number %d", i + 1); 3823 win_show(wins[i], label, i + 1); 3824 y += 3; 3825 x += 7; 3826 } 3827} 3828 3829/* Set the PANEL_DATA structures for individual panels */ 3830void set_user_ptrs(PANEL **panels, int n) 3831{ PANEL_DATA *ptrs; 3832 WINDOW *win; 3833 int x, y, w, h, i; 3834 char temp[80]; 3835 3836 ptrs = (PANEL_DATA *)calloc(n, sizeof(PANEL_DATA)); 3837 3838 for(i = 0;i < n; ++i) 3839 { win = panel_window(panels[i]); 3840 getbegyx(win, y, x); 3841 getmaxyx(win, h, w); 3842 ptrs[i].x = x; 3843 ptrs[i].y = y; 3844 ptrs[i].w = w; 3845 ptrs[i].h = h; 3846 sprintf(temp, "Window Number %d", i + 1); 3847 strcpy(ptrs[i].label, temp); 3848 ptrs[i].label_color = i + 1; 3849 if(i + 1 == n) 3850 ptrs[i].next = panels[0]; 3851 else 3852 ptrs[i].next = panels[i + 1]; 3853 set_panel_userptr(panels[i], &ptrs[i]); 3854 } 3855} 3856 3857/* Show the window with a border and a label */ 3858void win_show(WINDOW *win, char *label, int label_color) 3859{ int startx, starty, height, width; 3860 3861 getbegyx(win, starty, startx); 3862 getmaxyx(win, height, width); 3863 3864 box(win, 0, 0); 3865 mvwaddch(win, 2, 0, ACS_LTEE); 3866 mvwhline(win, 2, 1, ACS_HLINE, width - 2); 3867 mvwaddch(win, 2, width - 1, ACS_RTEE); 3868 3869 print_in_middle(win, 1, 0, width, label, COLOR_PAIR(label_color)); 3870} 3871 3872void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color) 3873{ int length, x, y; 3874 float temp; 3875 3876 if(win == NULL) 3877 win = stdscr; 3878 getyx(win, y, x); 3879 if(startx != 0) 3880 x = startx; 3881 if(starty != 0) 3882 y = starty; 3883 if(width == 0) 3884 width = 80; 3885 3886 length = strlen(string); 3887 temp = (width - length)/ 2; 3888 x = startx + (int)temp; 3889 wattron(win, color); 3890 mvwprintw(win, y, x, "%s", string); 3891 wattroff(win, color); 3892 refresh(); 3893}</span></pre> 3894 </div> 3895 3896 <p>Concentrate on the main while loop. Once it finds out 3897 the type of key pressed, it takes appropriate action. If 3898 'r' is pressed resizing mode is started. After this the new 3899 sizes are updated as the user presses the arrow keys. When 3900 the user presses <ENTER> present selection ends and 3901 panel is resized by using the concept explained. While in 3902 resizing mode the program doesn't show how the window is 3903 getting resized. It is left as an exercise to the reader to 3904 print a dotted border while it gets resized to a new 3905 position.</p> 3906 3907 <p>When the user presses 'm' the move mode starts. This is 3908 a bit simpler than resizing. As the arrow keys are pressed 3909 the new position is updated and pressing of <ENTER> 3910 causes the panel to be moved by calling the function 3911 move_panel().</p> 3912 3913 <p>In this program the user data which is represented as 3914 PANEL_DATA, plays very important role in finding the 3915 associated information with a panel. As written in the 3916 comments, the PANEL_DATA stores the panel sizes, label, 3917 label color and a pointer to the next panel in the 3918 cycle.</p> 3919 </div> 3920 3921 <div class="SECT2"> 3922 <hr> 3923 3924 <h3 class="SECT2"><a name="PANELSHOWHIDE" id= 3925 "PANELSHOWHIDE">16.6. Hiding and Showing Panels</a></h3> 3926 3927 <p>A Panel can be hidden by using the function 3928 hide_panel(). This function merely removes it form the 3929 stack of panels, thus hiding it on the screen once you do 3930 update_panels() and doupdate(). It doesn't destroy the 3931 PANEL structure associated with the hidden panel. It can be 3932 shown again by using the show_panel() function.</p> 3933 3934 <p>The following program shows the hiding of panels. Press 3935 'a' or 'b' or 'c' to show or hide first, second and third 3936 windows respectively. It uses a user data with a small 3937 variable hide, which keeps track of whether the window is 3938 hidden or not. For some reason the function <tt class= 3939 "LITERAL">panel_hidden()</tt> which tells whether a panel 3940 is hidden or not is not working. A bug report was also 3941 presented by Michael Andres <a href= 3942 "http://www.geocrawler.com/archives/3/344/1999/9/0/2643549/" 3943 target="_top">here</a></p> 3944 3945 <div class="EXAMPLE"> 3946 <a name="PPAHI" id="PPAHI"></a> 3947 <p><b>Example 17. Panel Hiding and Showing example</b> 3948 </p> 3949 3950 <pre class="PROGRAMLISTING"><span class= 3951 "INLINEMEDIAOBJECT">#include <string.h> 3952#include <panel.h> 3953 3954typedef struct _PANEL_DATA { 3955 int hide; /* TRUE if panel is hidden */ 3956}PANEL_DATA; 3957 3958#define NLINES 10 3959#define NCOLS 40 3960 3961void init_wins(WINDOW **wins, int n); 3962void win_show(WINDOW *win, char *label, int label_color); 3963void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color); 3964 3965int main() 3966{ WINDOW *my_wins[3]; 3967 PANEL *my_panels[3]; 3968 PANEL_DATA panel_datas[3]; 3969 PANEL_DATA *temp; 3970 int ch; 3971 3972 /* Initialize curses */ 3973 initscr(); 3974 start_color(); 3975 cbreak(); 3976 noecho(); 3977 keypad(stdscr, TRUE); 3978 3979 /* Initialize all the colors */ 3980 init_pair(1, COLOR_RED, COLOR_BLACK); 3981 init_pair(2, COLOR_GREEN, COLOR_BLACK); 3982 init_pair(3, COLOR_BLUE, COLOR_BLACK); 3983 init_pair(4, COLOR_CYAN, COLOR_BLACK); 3984 3985 init_wins(my_wins, 3); 3986 3987 /* Attach a panel to each window */ /* Order is bottom up */ 3988 my_panels[0] = new_panel(my_wins[0]); /* Push 0, order: stdscr-0 */ 3989 my_panels[1] = new_panel(my_wins[1]); /* Push 1, order: stdscr-0-1 */ 3990 my_panels[2] = new_panel(my_wins[2]); /* Push 2, order: stdscr-0-1-2 */ 3991 3992 /* Initialize panel data saying that nothing is hidden */ 3993 panel_datas[0].hide = FALSE; 3994 panel_datas[1].hide = FALSE; 3995 panel_datas[2].hide = FALSE; 3996 3997 set_panel_userptr(my_panels[0], &panel_datas[0]); 3998 set_panel_userptr(my_panels[1], &panel_datas[1]); 3999 set_panel_userptr(my_panels[2], &panel_datas[2]); 4000 4001 /* Update the stacking order. 2nd panel will be on top */ 4002 update_panels(); 4003 4004 /* Show it on the screen */ 4005 attron(COLOR_PAIR(4)); 4006 mvprintw(LINES - 3, 0, "Show or Hide a window with 'a'(first window) 'b'(Second Window) 'c'(Third Window)"); 4007 mvprintw(LINES - 2, 0, "F1 to Exit"); 4008 4009 attroff(COLOR_PAIR(4)); 4010 doupdate(); 4011 4012 while((ch = getch()) != KEY_F(1)) 4013 { switch(ch) 4014 { case 'a': 4015 temp = (PANEL_DATA *)panel_userptr(my_panels[0]); 4016 if(temp->hide == FALSE) 4017 { hide_panel(my_panels[0]); 4018 temp->hide = TRUE; 4019 } 4020 else 4021 { show_panel(my_panels[0]); 4022 temp->hide = FALSE; 4023 } 4024 break; 4025 case 'b': 4026 temp = (PANEL_DATA *)panel_userptr(my_panels[1]); 4027 if(temp->hide == FALSE) 4028 { hide_panel(my_panels[1]); 4029 temp->hide = TRUE; 4030 } 4031 else 4032 { show_panel(my_panels[1]); 4033 temp->hide = FALSE; 4034 } 4035 break; 4036 case 'c': 4037 temp = (PANEL_DATA *)panel_userptr(my_panels[2]); 4038 if(temp->hide == FALSE) 4039 { hide_panel(my_panels[2]); 4040 temp->hide = TRUE; 4041 } 4042 else 4043 { show_panel(my_panels[2]); 4044 temp->hide = FALSE; 4045 } 4046 break; 4047 } 4048 update_panels(); 4049 doupdate(); 4050 } 4051 endwin(); 4052 return 0; 4053} 4054 4055/* Put all the windows */ 4056void init_wins(WINDOW **wins, int n) 4057{ int x, y, i; 4058 char label[80]; 4059 4060 y = 2; 4061 x = 10; 4062 for(i = 0; i < n; ++i) 4063 { wins[i] = newwin(NLINES, NCOLS, y, x); 4064 sprintf(label, "Window Number %d", i + 1); 4065 win_show(wins[i], label, i + 1); 4066 y += 3; 4067 x += 7; 4068 } 4069} 4070 4071/* Show the window with a border and a label */ 4072void win_show(WINDOW *win, char *label, int label_color) 4073{ int startx, starty, height, width; 4074 4075 getbegyx(win, starty, startx); 4076 getmaxyx(win, height, width); 4077 4078 box(win, 0, 0); 4079 mvwaddch(win, 2, 0, ACS_LTEE); 4080 mvwhline(win, 2, 1, ACS_HLINE, width - 2); 4081 mvwaddch(win, 2, width - 1, ACS_RTEE); 4082 4083 print_in_middle(win, 1, 0, width, label, COLOR_PAIR(label_color)); 4084} 4085 4086void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color) 4087{ int length, x, y; 4088 float temp; 4089 4090 if(win == NULL) 4091 win = stdscr; 4092 getyx(win, y, x); 4093 if(startx != 0) 4094 x = startx; 4095 if(starty != 0) 4096 y = starty; 4097 if(width == 0) 4098 width = 80; 4099 4100 length = strlen(string); 4101 temp = (width - length)/ 2; 4102 x = startx + (int)temp; 4103 wattron(win, color); 4104 mvwprintw(win, y, x, "%s", string); 4105 wattroff(win, color); 4106 refresh(); 4107}</span></pre> 4108 </div> 4109 </div> 4110 4111 <div class="SECT2"> 4112 <hr> 4113 4114 <h3 class="SECT2"><a name="PANELABOVE" id= 4115 "PANELABOVE">16.7. panel_above() and panel_below() 4116 Functions</a></h3> 4117 4118 <p>The functions <tt class="LITERAL">panel_above()</tt> and 4119 <tt class="LITERAL">panel_below()</tt> can be used to find 4120 out the panel above and below a panel. If the argument to 4121 these functions is NULL, then they return a pointer to 4122 bottom panel and top panel respectively.</p> 4123 </div> 4124 </div> 4125 4126 <div class="SECT1"> 4127 <hr> 4128 4129 <h2 class="SECT1"><a name="MENUS" id="MENUS">17. Menus 4130 Library</a></h2> 4131 4132 <p>The menus library provides a nice extension to basic 4133 curses, through which you can create menus. It provides a set 4134 of functions to create menus. But they have to be customized 4135 to give a nicer look, with colors, etc. Let's get into the 4136 details.</p> 4137 4138 <p>A menu is a screen display that assists the user to choose 4139 some subset of a given set of items. To put it simple, a menu 4140 is a collection of items from which one or more items can be 4141 chosen. Some readers might not be aware of multiple item 4142 selection capability. Menu library provides functionality to 4143 write menus from which the user can chose more than one item 4144 as the preferred choice. This is dealt with in a later 4145 section. Now it is time for some rudiments.</p> 4146 4147 <div class="SECT2"> 4148 <hr> 4149 4150 <h3 class="SECT2"><a name="MENUBASICS" id= 4151 "MENUBASICS">17.1. The Basics</a></h3> 4152 4153 <p>To create menus, you first create items, and then post 4154 the menu to the display. After that, all the processing of 4155 user responses is done in an elegant function menu_driver() 4156 which is the work horse of any menu program.</p> 4157 4158 <p>The general flow of control of a menu program looks like 4159 this.</p> 4160 4161 <ol type="1"> 4162 <li> 4163 <p>Initialize curses</p> 4164 </li> 4165 4166 <li> 4167 <p>Create items using new_item(). You can specify a 4168 name and description for the items.</p> 4169 </li> 4170 4171 <li> 4172 <p>Create the menu with new_menu() by specifying the 4173 items to be attached with.</p> 4174 </li> 4175 4176 <li> 4177 <p>Post the menu with menu_post() and refresh the 4178 screen.</p> 4179 </li> 4180 4181 <li> 4182 <p>Process the user requests with a loop and do 4183 necessary updates to menu with menu_driver.</p> 4184 </li> 4185 4186 <li> 4187 <p>Unpost the menu with menu_unpost()</p> 4188 </li> 4189 4190 <li> 4191 <p>Free the memory allocated to menu by free_menu()</p> 4192 </li> 4193 4194 <li> 4195 <p>Free the memory allocated to the items with 4196 free_item()</p> 4197 </li> 4198 4199 <li> 4200 <p>End curses</p> 4201 </li> 4202 </ol> 4203 4204 <p>Let's see a program which prints a simple menu and 4205 updates the current selection with up, down arrows.</p> 4206 </div> 4207 4208 <div class="SECT2"> 4209 <hr> 4210 4211 <h3 class="SECT2"><a name="COMPILEMENUS" id= 4212 "COMPILEMENUS">17.2. Compiling With the Menu Library</a></h3> 4213 4214 <p>To use menu library functions, you have to include 4215 menu.h and to link the program with menu library the flag 4216 -lmenu should be added along with -lncurses in that 4217 order.</p> 4218 4219 <pre class="PROGRAMLISTING"> #include <menu.h> 4220 . 4221 . 4222 . 4223 4224 compile and link: gcc <program file> -lmenu -lncurses</pre> 4225 <div class="EXAMPLE"> 4226 <a name="MMESI" id="MMESI"></a> 4227 <p><b>Example 18. Menu Basics</b> 4228 </p> 4229 4230 <pre class="PROGRAMLISTING"><span class= 4231 "INLINEMEDIAOBJECT">#include <stdlib.h> 4232#include <curses.h> 4233#include <menu.h> 4234 4235#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 4236#define CTRLD 4 4237 4238char *choices[] = { 4239 "Choice 1", 4240 "Choice 2", 4241 "Choice 3", 4242 "Choice 4", 4243 "Exit", 4244 }; 4245 4246int main() 4247{ ITEM **my_items; 4248 int c; 4249 MENU *my_menu; 4250 int n_choices, i; 4251 ITEM *cur_item; 4252 4253 4254 initscr(); 4255 cbreak(); 4256 noecho(); 4257 keypad(stdscr, TRUE); 4258 4259 n_choices = ARRAY_SIZE(choices); 4260 my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *)); 4261 4262 for(i = 0; i < n_choices; ++i) 4263 my_items[i] = new_item(choices[i], choices[i]); 4264 my_items[n_choices] = (ITEM *)NULL; 4265 4266 my_menu = new_menu((ITEM **)my_items); 4267 mvprintw(LINES - 2, 0, "F1 to Exit"); 4268 post_menu(my_menu); 4269 refresh(); 4270 4271 while((c = getch()) != KEY_F(1)) 4272 { switch(c) 4273 { case KEY_DOWN: 4274 menu_driver(my_menu, REQ_DOWN_ITEM); 4275 break; 4276 case KEY_UP: 4277 menu_driver(my_menu, REQ_UP_ITEM); 4278 break; 4279 } 4280 } 4281 4282 free_item(my_items[0]); 4283 free_item(my_items[1]); 4284 free_menu(my_menu); 4285 endwin(); 4286} 4287 </span></pre> 4288 </div> 4289 4290 <p>This program demonstrates the basic concepts involved in 4291 creating a menu using menus library. First we create the 4292 items using new_item() and then attach them to the menu 4293 with new_menu() function. After posting the menu and 4294 refreshing the screen, the main processing loop starts. It 4295 reads user input and takes corresponding action. The 4296 function menu_driver() is the main work horse of the menu 4297 system. The second parameter to this function tells what's 4298 to be done with the menu. According to the parameter, 4299 menu_driver() does the corresponding task. The value can be 4300 either a menu navigational request, an ascii character, or 4301 a KEY_MOUSE special key associated with a mouse event.</p> 4302 4303 <p>The menu_driver accepts following navigational 4304 requests.</p> 4305 4306 <pre class= 4307 "PROGRAMLISTING"> REQ_LEFT_ITEM Move left to an item. 4308 REQ_RIGHT_ITEM Move right to an item. 4309 REQ_UP_ITEM Move up to an item. 4310 REQ_DOWN_ITEM Move down to an item. 4311 REQ_SCR_ULINE Scroll up a line. 4312 REQ_SCR_DLINE Scroll down a line. 4313 REQ_SCR_DPAGE Scroll down a page. 4314 REQ_SCR_UPAGE Scroll up a page. 4315 REQ_FIRST_ITEM Move to the first item. 4316 REQ_LAST_ITEM Move to the last item. 4317 REQ_NEXT_ITEM Move to the next item. 4318 REQ_PREV_ITEM Move to the previous item. 4319 REQ_TOGGLE_ITEM Select/deselect an item. 4320 REQ_CLEAR_PATTERN Clear the menu pattern buffer. 4321 REQ_BACK_PATTERN Delete the previous character from the pattern buffer. 4322 REQ_NEXT_MATCH Move to the next item matching the pattern match. 4323 REQ_PREV_MATCH Move to the previous item matching the pattern match. </pre> 4324 <p>Don't get overwhelmed by the number of options. We will 4325 see them slowly one after another. The options of interest 4326 in this example are REQ_UP_ITEM and REQ_DOWN_ITEM. These 4327 two options when passed to menu_driver, menu driver updates 4328 the current item to one item up or down respectively.</p> 4329 </div> 4330 4331 <div class="SECT2"> 4332 <hr> 4333 4334 <h3 class="SECT2"><a name="MENUDRIVER" id= 4335 "MENUDRIVER">17.3. Menu Driver: The work horse of the menu 4336 system</a></h3> 4337 4338 <p>As you have seen in the above example, menu_driver plays 4339 an important role in updating the menu. It is very 4340 important to understand various options it takes and what 4341 they do. As explained above, the second parameter to 4342 menu_driver() can be either a navigational request, a 4343 printable character or a KEY_MOUSE key. Let's dissect the 4344 different navigational requests.</p> 4345 4346 <ul> 4347 <li> 4348 <p><span class="emphasis"><i class= 4349 "EMPHASIS">REQ_LEFT_ITEM and REQ_RIGHT_ITEM</i></span> 4350 </p> 4351 4352 <p>A Menu can be displayed with multiple columns for 4353 more than one item. This can be done by using the 4354 <tt class="LITERAL">menu_format()</tt>function. When a 4355 multi columnar menu is displayed these requests cause 4356 the menu driver to move the current selection to left 4357 or right.</p> 4358 </li> 4359 4360 <li> 4361 <p><span class="emphasis"><i class= 4362 "EMPHASIS">REQ_UP_ITEM and REQ_DOWN_ITEM</i></span> 4363 </p> 4364 4365 <p>These two options you have seen in the above 4366 example. These options when given, makes the 4367 menu_driver to move the current selection to an item up 4368 or down.</p> 4369 </li> 4370 4371 <li> 4372 <p><span class="emphasis"><i class="EMPHASIS">REQ_SCR_* 4373 options</i></span> 4374 </p> 4375 4376 <p>The four options REQ_SCR_ULINE, REQ_SCR_DLINE, 4377 REQ_SCR_DPAGE, REQ_SCR_UPAGE are related to scrolling. 4378 If all the items in the menu cannot be displayed in the 4379 menu sub window, then the menu is scrollable. These 4380 requests can be given to the menu_driver to do the 4381 scrolling either one line up, down or one page down or 4382 up respectively.</p> 4383 </li> 4384 4385 <li> 4386 <p><span class="emphasis"><i class= 4387 "EMPHASIS">REQ_FIRST_ITEM, REQ_LAST_ITEM, REQ_NEXT_ITEM 4388 and REQ_PREV_ITEM</i></span> 4389 </p> 4390 4391 <p>These requests are self explanatory.</p> 4392 </li> 4393 4394 <li> 4395 <p><span class="emphasis"><i class= 4396 "EMPHASIS">REQ_TOGGLE_ITEM</i></span> 4397 </p> 4398 4399 <p>This request when given, toggles the present 4400 selection. This option is to be used only in a multi 4401 valued menu. So to use this request the option 4402 O_ONEVALUE must be off. This option can be made off or 4403 on with set_menu_opts().</p> 4404 </li> 4405 4406 <li> 4407 <p><span class="emphasis"><i class="EMPHASIS">Pattern 4408 Requests</i></span> 4409 </p> 4410 4411 <p>Every menu has an associated pattern buffer, which 4412 is used to find the nearest match to the ascii 4413 characters entered by the user. Whenever ascii 4414 characters are given to menu_driver, it puts in to the 4415 pattern buffer. It also tries to find the nearest match 4416 to the pattern in the items list and moves current 4417 selection to that item. The request REQ_CLEAR_PATTERN 4418 clears the pattern buffer. The request REQ_BACK_PATTERN 4419 deletes the previous character in the pattern buffer. 4420 In case the pattern matches more than one item then the 4421 matched items can be cycled through REQ_NEXT_MATCH and 4422 REQ_PREV_MATCH which move the current selection to the 4423 next and previous matches respectively.</p> 4424 </li> 4425 4426 <li> 4427 <p><span class="emphasis"><i class="EMPHASIS">Mouse 4428 Requests</i></span> 4429 </p> 4430 4431 <p>In case of KEY_MOUSE requests, according to the 4432 mouse position an action is taken accordingly. The 4433 action to be taken is explained in the man page as,</p> 4434 4435 <pre class="PROGRAMLISTING"><span class= 4436 "emphasis"><i class= 4437 "EMPHASIS"> If the second argument is the KEY_MOUSE special key, the 4438 associated mouse event is translated into one of the above 4439 pre-defined requests. Currently only clicks in the user 4440 window (e.g. inside the menu display area or the decora­ 4441 tion window) are handled. If you click above the display 4442 region of the menu, a REQ_SCR_ULINE is generated, if you 4443 doubleclick a REQ_SCR_UPAGE is generated and if you 4444 tripleclick a REQ_FIRST_ITEM is generated. If you click 4445 below the display region of the menu, a REQ_SCR_DLINE is 4446 generated, if you doubleclick a REQ_SCR_DPAGE is generated 4447 and if you tripleclick a REQ_LAST_ITEM is generated. If 4448 you click at an item inside the display area of the menu, 4449 the menu cursor is positioned to that item.</i></span></pre> 4450 </li> 4451 </ul> 4452 4453 <p>Each of the above requests will be explained in the 4454 following lines with several examples whenever 4455 appropriate.</p> 4456 </div> 4457 4458 <div class="SECT2"> 4459 <hr> 4460 4461 <h3 class="SECT2"><a name="MENUWINDOWS" id= 4462 "MENUWINDOWS">17.4. Menu Windows</a></h3> 4463 4464 <p>Every menu created is associated with a window and a sub 4465 window. The menu window displays any title or border 4466 associated with the menu. The menu sub window displays the 4467 menu items currently available for selection. But we didn't 4468 specify any window or sub window in the simple example. 4469 When a window is not specified, stdscr is taken as the main 4470 window, and then menu system calculates the sub window size 4471 required for the display of items. Then items are displayed 4472 in the calculated sub window. So let's play with these 4473 windows and display a menu with a border and a title.</p> 4474 4475 <div class="EXAMPLE"> 4476 <a name="MMEWI" id="MMEWI"></a> 4477 <p><b>Example 19. Menu Windows Usage example</b> 4478 </p> 4479 4480 <pre class="PROGRAMLISTING"><span class= 4481 "INLINEMEDIAOBJECT">#include <stdlib.h> 4482#include <string.h> 4483#include <menu.h> 4484 4485#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 4486#define CTRLD 4 4487 4488char *choices[] = { 4489 "Choice 1", 4490 "Choice 2", 4491 "Choice 3", 4492 "Choice 4", 4493 "Exit", 4494 (char *)NULL, 4495 }; 4496void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color); 4497 4498int main() 4499{ ITEM **my_items; 4500 int c; 4501 MENU *my_menu; 4502 WINDOW *my_menu_win; 4503 int n_choices, i; 4504 4505 /* Initialize curses */ 4506 initscr(); 4507 start_color(); 4508 cbreak(); 4509 noecho(); 4510 keypad(stdscr, TRUE); 4511 init_pair(1, COLOR_RED, COLOR_BLACK); 4512 4513 /* Create items */ 4514 n_choices = ARRAY_SIZE(choices); 4515 my_items = (ITEM **)calloc(n_choices, sizeof(ITEM *)); 4516 for(i = 0; i < n_choices; ++i) 4517 my_items[i] = new_item(choices[i], choices[i]); 4518 4519 /* Create menu */ 4520 my_menu = new_menu((ITEM **)my_items); 4521 4522 /* Create the window to be associated with the menu */ 4523 my_menu_win = newwin(10, 40, 4, 4); 4524 keypad(my_menu_win, TRUE); 4525 4526 /* Set main window and sub window */ 4527 set_menu_win(my_menu, my_menu_win); 4528 set_menu_sub(my_menu, derwin(my_menu_win, 6, 38, 3, 1)); 4529 4530 /* Set menu mark to the string " * " */ 4531 set_menu_mark(my_menu, " * "); 4532 4533 /* Print a border around the main window and print a title */ 4534 box(my_menu_win, 0, 0); 4535 print_in_middle(my_menu_win, 1, 0, 40, "My Menu", COLOR_PAIR(1)); 4536 mvwaddch(my_menu_win, 2, 0, ACS_LTEE); 4537 mvwhline(my_menu_win, 2, 1, ACS_HLINE, 38); 4538 mvwaddch(my_menu_win, 2, 39, ACS_RTEE); 4539 mvprintw(LINES - 2, 0, "F1 to exit"); 4540 refresh(); 4541 4542 /* Post the menu */ 4543 post_menu(my_menu); 4544 wrefresh(my_menu_win); 4545 4546 while((c = wgetch(my_menu_win)) != KEY_F(1)) 4547 { switch(c) 4548 { case KEY_DOWN: 4549 menu_driver(my_menu, REQ_DOWN_ITEM); 4550 break; 4551 case KEY_UP: 4552 menu_driver(my_menu, REQ_UP_ITEM); 4553 break; 4554 } 4555 wrefresh(my_menu_win); 4556 } 4557 4558 /* Unpost and free all the memory taken up */ 4559 unpost_menu(my_menu); 4560 free_menu(my_menu); 4561 for(i = 0; i < n_choices; ++i) 4562 free_item(my_items[i]); 4563 endwin(); 4564} 4565 4566void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color) 4567{ int length, x, y; 4568 float temp; 4569 4570 if(win == NULL) 4571 win = stdscr; 4572 getyx(win, y, x); 4573 if(startx != 0) 4574 x = startx; 4575 if(starty != 0) 4576 y = starty; 4577 if(width == 0) 4578 width = 80; 4579 4580 length = strlen(string); 4581 temp = (width - length)/ 2; 4582 x = startx + (int)temp; 4583 wattron(win, color); 4584 mvwprintw(win, y, x, "%s", string); 4585 wattroff(win, color); 4586 refresh(); 4587}</span></pre> 4588 </div> 4589 4590 <p>This example creates a menu with a title, border, a 4591 fancy line separating title and the items. As you can see, 4592 in order to attach a window to a menu the function 4593 set_menu_win() has to be used. Then we attach the sub 4594 window also. This displays the items in the sub window. You 4595 can also set the mark string which gets displayed to the 4596 left of the selected item with set_menu_mark().</p> 4597 </div> 4598 4599 <div class="SECT2"> 4600 <hr> 4601 4602 <h3 class="SECT2"><a name="SCROLLMENUS" id= 4603 "SCROLLMENUS">17.5. Scrolling Menus</a></h3> 4604 4605 <p>If the sub window given for a window is not big enough 4606 to show all the items, then the menu will be scrollable. 4607 When you are on the last item in the present list, if you 4608 send REQ_DOWN_ITEM, it gets translated into REQ_SCR_DLINE 4609 and the menu scrolls by one item. You can manually give 4610 REQ_SCR_ operations to do scrolling. Let's see how it can 4611 be done.</p> 4612 4613 <div class="EXAMPLE"> 4614 <a name="MMESC" id="MMESC"></a> 4615 <p><b>Example 20. Scrolling Menus example</b> 4616 </p> 4617 4618 <pre class="PROGRAMLISTING"><span class= 4619 "INLINEMEDIAOBJECT">#include <stdlib.h> 4620#include <string.h> 4621#include <curses.h> 4622#include <menu.h> 4623 4624#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 4625#define CTRLD 4 4626 4627char *choices[] = { 4628 "Choice 1", 4629 "Choice 2", 4630 "Choice 3", 4631 "Choice 4", 4632 "Choice 5", 4633 "Choice 6", 4634 "Choice 7", 4635 "Choice 8", 4636 "Choice 9", 4637 "Choice 10", 4638 "Exit", 4639 (char *)NULL, 4640 }; 4641void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color); 4642 4643int main() 4644{ ITEM **my_items; 4645 int c; 4646 MENU *my_menu; 4647 WINDOW *my_menu_win; 4648 int n_choices, i; 4649 4650 /* Initialize curses */ 4651 initscr(); 4652 start_color(); 4653 cbreak(); 4654 noecho(); 4655 keypad(stdscr, TRUE); 4656 init_pair(1, COLOR_RED, COLOR_BLACK); 4657 init_pair(2, COLOR_CYAN, COLOR_BLACK); 4658 4659 /* Create items */ 4660 n_choices = ARRAY_SIZE(choices); 4661 my_items = (ITEM **)calloc(n_choices, sizeof(ITEM *)); 4662 for(i = 0; i < n_choices; ++i) 4663 my_items[i] = new_item(choices[i], choices[i]); 4664 4665 /* Create menu */ 4666 my_menu = new_menu((ITEM **)my_items); 4667 4668 /* Create the window to be associated with the menu */ 4669 my_menu_win = newwin(10, 40, 4, 4); 4670 keypad(my_menu_win, TRUE); 4671 4672 /* Set main window and sub window */ 4673 set_menu_win(my_menu, my_menu_win); 4674 set_menu_sub(my_menu, derwin(my_menu_win, 6, 38, 3, 1)); 4675 set_menu_format(my_menu, 5, 1); 4676 4677 /* Set menu mark to the string " * " */ 4678 set_menu_mark(my_menu, " * "); 4679 4680 /* Print a border around the main window and print a title */ 4681 box(my_menu_win, 0, 0); 4682 print_in_middle(my_menu_win, 1, 0, 40, "My Menu", COLOR_PAIR(1)); 4683 mvwaddch(my_menu_win, 2, 0, ACS_LTEE); 4684 mvwhline(my_menu_win, 2, 1, ACS_HLINE, 38); 4685 mvwaddch(my_menu_win, 2, 39, ACS_RTEE); 4686 4687 /* Post the menu */ 4688 post_menu(my_menu); 4689 wrefresh(my_menu_win); 4690 4691 attron(COLOR_PAIR(2)); 4692 mvprintw(LINES - 2, 0, "Use PageUp and PageDown to scroll down or up a page of items"); 4693 mvprintw(LINES - 1, 0, "Arrow Keys to navigate (F1 to Exit)"); 4694 attroff(COLOR_PAIR(2)); 4695 refresh(); 4696 4697 while((c = wgetch(my_menu_win)) != KEY_F(1)) 4698 { switch(c) 4699 { case KEY_DOWN: 4700 menu_driver(my_menu, REQ_DOWN_ITEM); 4701 break; 4702 case KEY_UP: 4703 menu_driver(my_menu, REQ_UP_ITEM); 4704 break; 4705 case KEY_NPAGE: 4706 menu_driver(my_menu, REQ_SCR_DPAGE); 4707 break; 4708 case KEY_PPAGE: 4709 menu_driver(my_menu, REQ_SCR_UPAGE); 4710 break; 4711 } 4712 wrefresh(my_menu_win); 4713 } 4714 4715 /* Unpost and free all the memory taken up */ 4716 unpost_menu(my_menu); 4717 free_menu(my_menu); 4718 for(i = 0; i < n_choices; ++i) 4719 free_item(my_items[i]); 4720 endwin(); 4721} 4722 4723void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color) 4724{ int length, x, y; 4725 float temp; 4726 4727 if(win == NULL) 4728 win = stdscr; 4729 getyx(win, y, x); 4730 if(startx != 0) 4731 x = startx; 4732 if(starty != 0) 4733 y = starty; 4734 if(width == 0) 4735 width = 80; 4736 4737 length = strlen(string); 4738 temp = (width - length)/ 2; 4739 x = startx + (int)temp; 4740 wattron(win, color); 4741 mvwprintw(win, y, x, "%s", string); 4742 wattroff(win, color); 4743 refresh(); 4744}</span></pre> 4745 </div> 4746 4747 <p>This program is self-explanatory. In this example the 4748 number of choices has been increased to ten, which is 4749 larger than our sub window size which can hold 6 items. 4750 This message has to be explicitly conveyed to the menu 4751 system with the function set_menu_format(). In here we 4752 specify the number of rows and columns we want to be 4753 displayed for a single page. We can specify any number of 4754 items to be shown, in the rows variables, if it is less 4755 than the height of the sub window. If the key pressed by 4756 the user is a PAGE UP or PAGE DOWN, the menu is scrolled a 4757 page due to the requests (REQ_SCR_DPAGE and REQ_SCR_UPAGE) 4758 given to menu_driver().</p> 4759 </div> 4760 4761 <div class="SECT2"> 4762 <hr> 4763 4764 <h3 class="SECT2"><a name="MULTICOLUMN" id= 4765 "MULTICOLUMN">17.6. Multi Columnar Menus</a></h3> 4766 4767 <p>In the above example you have seen how to use the 4768 function set_menu_format(). I didn't mention what the cols 4769 variable (third parameter) does. Well, If your sub window 4770 is wide enough, you can opt to display more than one item 4771 per row. This can be specified in the cols variable. To 4772 make things simpler, the following example doesn't show 4773 descriptions for the items.</p> 4774 4775 <div class="EXAMPLE"> 4776 <a name="MMEMUCO" id="MMEMUCO"></a> 4777 <p><b>Example 21. Milt Columnar Menus Example</b> 4778 </p> 4779 4780 <pre class="PROGRAMLISTING"><span class= 4781 "INLINEMEDIAOBJECT">#include <stdlib.h> 4782#include <curses.h> 4783#include <menu.h> 4784 4785#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 4786#define CTRLD 4 4787 4788char *choices[] = { 4789 "Choice 1", "Choice 2", "Choice 3", "Choice 4", "Choice 5", 4790 "Choice 6", "Choice 7", "Choice 8", "Choice 9", "Choice 10", 4791 "Choice 11", "Choice 12", "Choice 13", "Choice 14", "Choice 15", 4792 "Choice 16", "Choice 17", "Choice 18", "Choice 19", "Choice 20", 4793 "Exit", 4794 (char *)NULL, 4795 }; 4796 4797int main() 4798{ ITEM **my_items; 4799 int c; 4800 MENU *my_menu; 4801 WINDOW *my_menu_win; 4802 int n_choices, i; 4803 4804 /* Initialize curses */ 4805 initscr(); 4806 start_color(); 4807 cbreak(); 4808 noecho(); 4809 keypad(stdscr, TRUE); 4810 init_pair(1, COLOR_RED, COLOR_BLACK); 4811 init_pair(2, COLOR_CYAN, COLOR_BLACK); 4812 4813 /* Create items */ 4814 n_choices = ARRAY_SIZE(choices); 4815 my_items = (ITEM **)calloc(n_choices, sizeof(ITEM *)); 4816 for(i = 0; i < n_choices; ++i) 4817 my_items[i] = new_item(choices[i], choices[i]); 4818 4819 /* Create menu */ 4820 my_menu = new_menu((ITEM **)my_items); 4821 4822 /* Set menu option not to show the description */ 4823 menu_opts_off(my_menu, O_SHOWDESC); 4824 4825 /* Create the window to be associated with the menu */ 4826 my_menu_win = newwin(10, 70, 4, 4); 4827 keypad(my_menu_win, TRUE); 4828 4829 /* Set main window and sub window */ 4830 set_menu_win(my_menu, my_menu_win); 4831 set_menu_sub(my_menu, derwin(my_menu_win, 6, 68, 3, 1)); 4832 set_menu_format(my_menu, 5, 3); 4833 set_menu_mark(my_menu, " * "); 4834 4835 /* Print a border around the main window and print a title */ 4836 box(my_menu_win, 0, 0); 4837 4838 attron(COLOR_PAIR(2)); 4839 mvprintw(LINES - 3, 0, "Use PageUp and PageDown to scroll"); 4840 mvprintw(LINES - 2, 0, "Use Arrow Keys to navigate (F1 to Exit)"); 4841 attroff(COLOR_PAIR(2)); 4842 refresh(); 4843 4844 /* Post the menu */ 4845 post_menu(my_menu); 4846 wrefresh(my_menu_win); 4847 4848 while((c = wgetch(my_menu_win)) != KEY_F(1)) 4849 { switch(c) 4850 { case KEY_DOWN: 4851 menu_driver(my_menu, REQ_DOWN_ITEM); 4852 break; 4853 case KEY_UP: 4854 menu_driver(my_menu, REQ_UP_ITEM); 4855 break; 4856 case KEY_LEFT: 4857 menu_driver(my_menu, REQ_LEFT_ITEM); 4858 break; 4859 case KEY_RIGHT: 4860 menu_driver(my_menu, REQ_RIGHT_ITEM); 4861 break; 4862 case KEY_NPAGE: 4863 menu_driver(my_menu, REQ_SCR_DPAGE); 4864 break; 4865 case KEY_PPAGE: 4866 menu_driver(my_menu, REQ_SCR_UPAGE); 4867 break; 4868 } 4869 wrefresh(my_menu_win); 4870 } 4871 4872 /* Unpost and free all the memory taken up */ 4873 unpost_menu(my_menu); 4874 free_menu(my_menu); 4875 for(i = 0; i < n_choices; ++i) 4876 free_item(my_items[i]); 4877 endwin(); 4878}</span></pre> 4879 </div> 4880 4881 <p>Watch the function call to set_menu_format(). It 4882 specifies the number of columns to be 3, thus displaying 3 4883 items per row. We have also switched off the showing 4884 descriptions with the function menu_opts_off(). There are 4885 couple of functions set_menu_opts(), menu_opts_on() and 4886 menu_opts() which can be used to manipulate menu options. 4887 The following menu options can be specified.</p> 4888 4889 <pre class="PROGRAMLISTING"> O_ONEVALUE 4890 Only one item can be selected for this menu. 4891 4892 O_SHOWDESC 4893 Display the item descriptions when the menu is 4894 posted. 4895 4896 O_ROWMAJOR 4897 Display the menu in row-major order. 4898 4899 O_IGNORECASE 4900 Ignore the case when pattern-matching. 4901 4902 O_SHOWMATCH 4903 Move the cursor to within the item name while pat­ 4904 tern-matching. 4905 4906 O_NONCYCLIC 4907 Don't wrap around next-item and previous-item, 4908 requests to the other end of the menu.</pre> 4909 <p>All options are on by default. You can switch specific 4910 attributes on or off with menu_opts_on() and 4911 menu_opts_off() functions. You can also use set_menu_opts() 4912 to directly specify the options. The argument to this 4913 function should be a OR ed value of some of those above 4914 constants. The function menu_opts() can be used to find out 4915 a menu's present options.</p> 4916 </div> 4917 4918 <div class="SECT2"> 4919 <hr> 4920 4921 <h3 class="SECT2"><a name="MULTIVALUEMENUS" id= 4922 "MULTIVALUEMENUS">17.7. Multi Valued Menus</a></h3> 4923 4924 <p>You might be wondering what if you switch off the option 4925 O_ONEVALUE. Then the menu becomes multi-valued. That means 4926 you can select more than one item. This brings us to the 4927 request REQ_TOGGLE_ITEM. Let's see it in action.</p> 4928 4929 <div class="EXAMPLE"> 4930 <a name="MMETO" id="MMETO"></a> 4931 <p><b>Example 22. Multi Valued Menus example</b> 4932 </p> 4933 4934 <pre class="PROGRAMLISTING"><span class= 4935 "INLINEMEDIAOBJECT">#include <stdlib.h> 4936#include <string.h> 4937#include <curses.h> 4938#include <menu.h> 4939 4940#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 4941#define CTRLD 4 4942 4943char *choices[] = { 4944 "Choice 1", 4945 "Choice 2", 4946 "Choice 3", 4947 "Choice 4", 4948 "Choice 5", 4949 "Choice 6", 4950 "Choice 7", 4951 "Exit", 4952 }; 4953 4954int main() 4955{ ITEM **my_items; 4956 int c; 4957 MENU *my_menu; 4958 int n_choices, i; 4959 ITEM *cur_item; 4960 4961 /* Initialize curses */ 4962 initscr(); 4963 cbreak(); 4964 noecho(); 4965 keypad(stdscr, TRUE); 4966 4967 /* Initialize items */ 4968 n_choices = ARRAY_SIZE(choices); 4969 my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *)); 4970 for(i = 0; i < n_choices; ++i) 4971 my_items[i] = new_item(choices[i], choices[i]); 4972 my_items[n_choices] = (ITEM *)NULL; 4973 4974 my_menu = new_menu((ITEM **)my_items); 4975 4976 /* Make the menu multi valued */ 4977 menu_opts_off(my_menu, O_ONEVALUE); 4978 4979 mvprintw(LINES - 3, 0, "Use <SPACE> to select or unselect an item."); 4980 mvprintw(LINES - 2, 0, "<ENTER> to see presently selected items(F1 to Exit)"); 4981 post_menu(my_menu); 4982 refresh(); 4983 4984 while((c = getch()) != KEY_F(1)) 4985 { switch(c) 4986 { case KEY_DOWN: 4987 menu_driver(my_menu, REQ_DOWN_ITEM); 4988 break; 4989 case KEY_UP: 4990 menu_driver(my_menu, REQ_UP_ITEM); 4991 break; 4992 case ' ': 4993 menu_driver(my_menu, REQ_TOGGLE_ITEM); 4994 break; 4995 case 10: /* Enter */ 4996 { char temp[200]; 4997 ITEM **items; 4998 4999 items = menu_items(my_menu); 5000 temp[0] = '\0'; 5001 for(i = 0; i < item_count(my_menu); ++i) 5002 if(item_value(items[i]) == TRUE) 5003 { strcat(temp, item_name(items[i])); 5004 strcat(temp, " "); 5005 } 5006 move(20, 0); 5007 clrtoeol(); 5008 mvprintw(20, 0, temp); 5009 refresh(); 5010 } 5011 break; 5012 } 5013 } 5014 5015 free_item(my_items[0]); 5016 free_item(my_items[1]); 5017 free_menu(my_menu); 5018 endwin(); 5019} 5020 </span></pre> 5021 </div> 5022 5023 <p>Whew, A lot of new functions. Let's take them one after 5024 another. Firstly, the REQ_TOGGLE_ITEM. In a multi-valued 5025 menu, the user should be allowed to select or un select 5026 more than one item. The request REQ_TOGGLE_ITEM toggles the 5027 present selection. In this case when space is pressed 5028 REQ_TOGGLE_ITEM request is sent to menu_driver to achieve 5029 the result.</p> 5030 5031 <p>Now when the user presses <ENTER> we show the 5032 items he presently selected. First we find out the items 5033 associated with the menu using the function menu_items(). 5034 Then we loop through the items to find out if the item is 5035 selected or not. The function item_value() returns TRUE if 5036 an item is selected. The function item_count() returns the 5037 number of items in the menu. The item name can be found 5038 with item_name(). You can also find the description 5039 associated with an item using item_description().</p> 5040 </div> 5041 5042 <div class="SECT2"> 5043 <hr> 5044 5045 <h3 class="SECT2"><a name="MENUOPT" id="MENUOPT">17.8. Menu 5046 Options</a></h3> 5047 5048 <p>Well, by this time you must be itching for some 5049 difference in your menu, with lots of functionality. I 5050 know. You want Colors !!!. You want to create nice menus 5051 similar to those text mode <a href= 5052 "http://www.jersey.net/~debinjoe/games/" target="_top">dos 5053 games</a>. The functions set_menu_fore() and 5054 set_menu_back() can be used to change the attribute of the 5055 selected item and unselected item. The names are 5056 misleading. They don't change menu's foreground or 5057 background which would have been useless.</p> 5058 5059 <p>The function set_menu_grey() can be used to set the 5060 display attribute for the non-selectable items in the menu. 5061 This brings us to the interesting option for an item the 5062 one and only O_SELECTABLE. We can turn it off by the 5063 function item_opts_off() and after that that item is not 5064 selectable. It is like a grayed item in those fancy windows 5065 menus. Let's put these concepts in practice with this 5066 example</p> 5067 5068 <div class="EXAMPLE"> 5069 <a name="MMEAT" id="MMEAT"></a> 5070 <p><b>Example 23. Menu Options example</b> 5071 </p> 5072 5073 <pre class="PROGRAMLISTING"><span class= 5074 "INLINEMEDIAOBJECT">#include <stdlib.h> 5075#include <menu.h> 5076 5077#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 5078#define CTRLD 4 5079 5080char *choices[] = { 5081 "Choice 1", 5082 "Choice 2", 5083 "Choice 3", 5084 "Choice 4", 5085 "Choice 5", 5086 "Choice 6", 5087 "Choice 7", 5088 "Exit", 5089 }; 5090 5091int main() 5092{ ITEM **my_items; 5093 int c; 5094 MENU *my_menu; 5095 int n_choices, i; 5096 ITEM *cur_item; 5097 5098 /* Initialize curses */ 5099 initscr(); 5100 start_color(); 5101 cbreak(); 5102 noecho(); 5103 keypad(stdscr, TRUE); 5104 init_pair(1, COLOR_RED, COLOR_BLACK); 5105 init_pair(2, COLOR_GREEN, COLOR_BLACK); 5106 init_pair(3, COLOR_MAGENTA, COLOR_BLACK); 5107 5108 /* Initialize items */ 5109 n_choices = ARRAY_SIZE(choices); 5110 my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *)); 5111 for(i = 0; i < n_choices; ++i) 5112 my_items[i] = new_item(choices[i], choices[i]); 5113 my_items[n_choices] = (ITEM *)NULL; 5114 item_opts_off(my_items[3], O_SELECTABLE); 5115 item_opts_off(my_items[6], O_SELECTABLE); 5116 5117 /* Create menu */ 5118 my_menu = new_menu((ITEM **)my_items); 5119 5120 /* Set fore ground and back ground of the menu */ 5121 set_menu_fore(my_menu, COLOR_PAIR(1) | A_REVERSE); 5122 set_menu_back(my_menu, COLOR_PAIR(2)); 5123 set_menu_grey(my_menu, COLOR_PAIR(3)); 5124 5125 /* Post the menu */ 5126 mvprintw(LINES - 3, 0, "Press <ENTER> to see the option selected"); 5127 mvprintw(LINES - 2, 0, "Up and Down arrow keys to navigate (F1 to Exit)"); 5128 post_menu(my_menu); 5129 refresh(); 5130 5131 while((c = getch()) != KEY_F(1)) 5132 { switch(c) 5133 { case KEY_DOWN: 5134 menu_driver(my_menu, REQ_DOWN_ITEM); 5135 break; 5136 case KEY_UP: 5137 menu_driver(my_menu, REQ_UP_ITEM); 5138 break; 5139 case 10: /* Enter */ 5140 move(20, 0); 5141 clrtoeol(); 5142 mvprintw(20, 0, "Item selected is : %s", 5143 item_name(current_item(my_menu))); 5144 pos_menu_cursor(my_menu); 5145 break; 5146 } 5147 } 5148 unpost_menu(my_menu); 5149 for(i = 0; i < n_choices; ++i) 5150 free_item(my_items[i]); 5151 free_menu(my_menu); 5152 endwin(); 5153} 5154 </span></pre> 5155 </div> 5156 </div> 5157 5158 <div class="SECT2"> 5159 <hr> 5160 5161 <h3 class="SECT2"><a name="MENUUSERPTR" id= 5162 "MENUUSERPTR">17.9. The useful User Pointer</a></h3> 5163 5164 <p>We can associate a user pointer with each item in the 5165 menu. It works the same way as user pointer in panels. It 5166 is not touched by menu system. You can store any thing you 5167 like in that. I usually use it to store the function to be 5168 executed when the menu option is chosen (It is selected and 5169 may be the user pressed <ENTER>);</p> 5170 5171 <div class="EXAMPLE"> 5172 <a name="MMEUS" id="MMEUS"></a> 5173 <p><b>Example 24. Menu User Pointer Usage</b> 5174 </p> 5175 5176 <pre class="PROGRAMLISTING"><span class= 5177 "INLINEMEDIAOBJECT">#include <stdlib.h> 5178#include <curses.h> 5179#include <menu.h> 5180 5181#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 5182#define CTRLD 4 5183 5184char *choices[] = { 5185 "Choice 1", 5186 "Choice 2", 5187 "Choice 3", 5188 "Choice 4", 5189 "Choice 5", 5190 "Choice 6", 5191 "Choice 7", 5192 "Exit", 5193 }; 5194void func(char *name); 5195 5196int main() 5197{ ITEM **my_items; 5198 int c; 5199 MENU *my_menu; 5200 int n_choices, i; 5201 ITEM *cur_item; 5202 5203 /* Initialize curses */ 5204 initscr(); 5205 start_color(); 5206 cbreak(); 5207 noecho(); 5208 keypad(stdscr, TRUE); 5209 init_pair(1, COLOR_RED, COLOR_BLACK); 5210 init_pair(2, COLOR_GREEN, COLOR_BLACK); 5211 init_pair(3, COLOR_MAGENTA, COLOR_BLACK); 5212 5213 /* Initialize items */ 5214 n_choices = ARRAY_SIZE(choices); 5215 my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *)); 5216 for(i = 0; i < n_choices; ++i) 5217 { my_items[i] = new_item(choices[i], choices[i]); 5218 /* Set the user pointer */ 5219 set_item_userptr(my_items[i], func); 5220 } 5221 my_items[n_choices] = (ITEM *)NULL; 5222 5223 /* Create menu */ 5224 my_menu = new_menu((ITEM **)my_items); 5225 5226 /* Post the menu */ 5227 mvprintw(LINES - 3, 0, "Press <ENTER> to see the option selected"); 5228 mvprintw(LINES - 2, 0, "Up and Down arrow keys to navigate (F1 to Exit)"); 5229 post_menu(my_menu); 5230 refresh(); 5231 5232 while((c = getch()) != KEY_F(1)) 5233 { switch(c) 5234 { case KEY_DOWN: 5235 menu_driver(my_menu, REQ_DOWN_ITEM); 5236 break; 5237 case KEY_UP: 5238 menu_driver(my_menu, REQ_UP_ITEM); 5239 break; 5240 case 10: /* Enter */ 5241 { ITEM *cur; 5242 void (*p)(char *); 5243 5244 cur = current_item(my_menu); 5245 p = item_userptr(cur); 5246 p((char *)item_name(cur)); 5247 pos_menu_cursor(my_menu); 5248 break; 5249 } 5250 break; 5251 } 5252 } 5253 unpost_menu(my_menu); 5254 for(i = 0; i < n_choices; ++i) 5255 free_item(my_items[i]); 5256 free_menu(my_menu); 5257 endwin(); 5258} 5259 5260void func(char *name) 5261{ move(20, 0); 5262 clrtoeol(); 5263 mvprintw(20, 0, "Item selected is : %s", name); 5264} </span></pre> 5265 </div> 5266 </div> 5267 </div> 5268 5269 <div class="SECT1"> 5270 <hr> 5271 5272 <h2 class="SECT1"><a name="FORMS" id="FORMS">18. Forms 5273 Library</a></h2> 5274 5275 <p>Well. If you have seen those forms on web pages which take 5276 input from users and do various kinds of things, you might be 5277 wondering how would any one create such forms in text mode 5278 display. It is quite difficult to write those nifty forms in 5279 plain ncurses. Forms library tries to provide a basic frame 5280 work to build and maintain forms with ease. It has lot of 5281 features(functions) which manage validation, dynamic 5282 expansion of fields, etc. Let's see it in full flow.</p> 5283 5284 <p>A form is a collection of fields; each field can be either 5285 a label(static text) or a data-entry location. The forms also 5286 library provides functions to divide forms into multiple 5287 pages.</p> 5288 5289 <div class="SECT2"> 5290 <hr> 5291 5292 <h3 class="SECT2"><a name="FORMBASICS" id= 5293 "FORMBASICS">18.1. The Basics</a></h3> 5294 5295 <p>Forms are created in much the same way as menus. First 5296 the fields related to the form are created with 5297 new_field(). You can set options for the fields, so that 5298 they can be displayed with some fancy attributes, validated 5299 before the field looses focus, etc. Then the fields are 5300 attached to form. After this, the form can be posted to 5301 display and is ready to receive inputs. On the similar 5302 lines to menu_driver(), the form is manipulated with 5303 form_driver(). We can send requests to form_driver to move 5304 focus to a certain field, move cursor to end of the field 5305 etc. After the user enters values in the fields and 5306 validation done, form can be unposted and memory allocated 5307 can be freed.</p> 5308 5309 <p>The general flow of control of a forms program looks 5310 like this.</p> 5311 5312 <ol type="1"> 5313 <li> 5314 <p>Initialize curses</p> 5315 </li> 5316 5317 <li> 5318 <p>Create fields using new_field(). You can specify the 5319 height and width of the field, and its position on the 5320 form.</p> 5321 </li> 5322 5323 <li> 5324 <p>Create the forms with new_form() by specifying the 5325 fields to be attached with.</p> 5326 </li> 5327 5328 <li> 5329 <p>Post the form with form_post() and refresh the 5330 screen.</p> 5331 </li> 5332 5333 <li> 5334 <p>Process the user requests with a loop and do 5335 necessary updates to form with form_driver.</p> 5336 </li> 5337 5338 <li> 5339 <p>Unpost the menu with form_unpost()</p> 5340 </li> 5341 5342 <li> 5343 <p>Free the memory allocated to menu by free_form()</p> 5344 </li> 5345 5346 <li> 5347 <p>Free the memory allocated to the items with 5348 free_field()</p> 5349 </li> 5350 5351 <li> 5352 <p>End curses</p> 5353 </li> 5354 </ol> 5355 5356 <p>As you can see, working with forms library is much 5357 similar to handling menu library. The following examples 5358 will explore various aspects of form processing. Let's 5359 start the journey with a simple example. first.</p> 5360 </div> 5361 5362 <div class="SECT2"> 5363 <hr> 5364 5365 <h3 class="SECT2"><a name="COMPILEFORMS" id= 5366 "COMPILEFORMS">18.2. Compiling With the Forms Library</a></h3> 5367 5368 <p>To use forms library functions, you have to include 5369 form.h and to link the program with forms library the flag 5370 -lform should be added along with -lncurses in that 5371 order.</p> 5372 5373 <pre class="PROGRAMLISTING"> #include <form.h> 5374 . 5375 . 5376 . 5377 5378 compile and link: gcc <program file> -lform -lncurses</pre> 5379 <div class="EXAMPLE"> 5380 <a name="FFOSI" id="FFOSI"></a> 5381 <p><b>Example 25. Forms Basics</b> 5382 </p> 5383 5384 <pre class="PROGRAMLISTING"><span class= 5385 "INLINEMEDIAOBJECT">#include <form.h> 5386 5387int main() 5388{ FIELD *field[3]; 5389 FORM *my_form; 5390 int ch; 5391 5392 /* Initialize curses */ 5393 initscr(); 5394 cbreak(); 5395 noecho(); 5396 keypad(stdscr, TRUE); 5397 5398 /* Initialize the fields */ 5399 field[0] = new_field(1, 10, 4, 18, 0, 0); 5400 field[1] = new_field(1, 10, 6, 18, 0, 0); 5401 field[2] = NULL; 5402 5403 /* Set field options */ 5404 set_field_back(field[0], A_UNDERLINE); /* Print a line for the option */ 5405 field_opts_off(field[0], O_AUTOSKIP); /* Don't go to next field when this */ 5406 /* Field is filled up */ 5407 set_field_back(field[1], A_UNDERLINE); 5408 field_opts_off(field[1], O_AUTOSKIP); 5409 5410 /* Create the form and post it */ 5411 my_form = new_form(field); 5412 post_form(my_form); 5413 refresh(); 5414 5415 mvprintw(4, 10, "Value 1:"); 5416 mvprintw(6, 10, "Value 2:"); 5417 refresh(); 5418 5419 /* Loop through to get user requests */ 5420 while((ch = getch()) != KEY_F(1)) 5421 { switch(ch) 5422 { case KEY_DOWN: 5423 /* Go to next field */ 5424 form_driver(my_form, REQ_NEXT_FIELD); 5425 /* Go to the end of the present buffer */ 5426 /* Leaves nicely at the last character */ 5427 form_driver(my_form, REQ_END_LINE); 5428 break; 5429 case KEY_UP: 5430 /* Go to previous field */ 5431 form_driver(my_form, REQ_PREV_FIELD); 5432 form_driver(my_form, REQ_END_LINE); 5433 break; 5434 default: 5435 /* If this is a normal character, it gets */ 5436 /* Printed */ 5437 form_driver(my_form, ch); 5438 break; 5439 } 5440 } 5441 5442 /* Un post form and free the memory */ 5443 unpost_form(my_form); 5444 free_form(my_form); 5445 free_field(field[0]); 5446 free_field(field[1]); 5447 5448 endwin(); 5449 return 0; 5450}</span></pre> 5451 </div> 5452 5453 <p>Above example is pretty straight forward. It creates two 5454 fields with <tt class="LITERAL">new_field()</tt>. 5455 new_field() takes height, width, starty, startx, number of 5456 offscreen rows and number of additional working buffers. 5457 The fifth argument number of offscreen rows specifies how 5458 much of the field to be shown. If it is zero, the entire 5459 field is always displayed otherwise the form will be 5460 scrollable when the user accesses not displayed parts of 5461 the field. The forms library allocates one buffer per field 5462 to store the data user enters. Using the last parameter to 5463 new_field() we can specify it to allocate some additional 5464 buffers. These can be used for any purpose you like.</p> 5465 5466 <p>After creating the fields, back ground attribute of both 5467 of them is set to an underscore with set_field_back(). The 5468 AUTOSKIP option is turned off using field_opts_off(). If 5469 this option is turned on, focus will move to the next field 5470 in the form once the active field is filled up 5471 completely.</p> 5472 5473 <p>After attaching the fields to the form, it is posted. 5474 Here on, user inputs are processed in the while loop, by 5475 making corresponding requests to form_driver. The details 5476 of all the requests to the form_driver() are explained 5477 later.</p> 5478 </div> 5479 5480 <div class="SECT2"> 5481 <hr> 5482 5483 <h3 class="SECT2"><a name="PLAYFIELDS" id= 5484 "PLAYFIELDS">18.3. Playing with Fields</a></h3> 5485 5486 <p>Each form field is associated with a lot of attributes. 5487 They can be manipulated to get the required effect and to 5488 have fun !!!. So why wait?</p> 5489 5490 <div class="SECT3"> 5491 <hr> 5492 5493 <h4 class="SECT3"><a name="FETCHINFO" id= 5494 "FETCHINFO">18.3.1. Fetching Size and Location of 5495 Field</a></h4> 5496 5497 <p>The parameters we have given at the time of creation 5498 of a field can be retrieved with field_info(). It returns 5499 height, width, starty, startx, number of offscreen rows, 5500 and number of additional buffers into the parameters 5501 given to it. It is a sort of inverse of new_field().</p> 5502 5503 <pre class= 5504 "PROGRAMLISTING">int field_info( FIELD *field, /* field from which to fetch */ 5505 int *height, *int width, /* field size */ 5506 int *top, int *left, /* upper left corner */ 5507 int *offscreen, /* number of offscreen rows */ 5508 int *nbuf); /* number of working buffers */</pre> 5509 </div> 5510 5511 <div class="SECT3"> 5512 <hr> 5513 5514 <h4 class="SECT3"><a name="MOVEFIELD" id= 5515 "MOVEFIELD">18.3.2. Moving the field</a></h4> 5516 5517 <p>The location of the field can be moved to a different 5518 position with move_field().</p> 5519 5520 <pre class= 5521 "PROGRAMLISTING">int move_field( FIELD *field, /* field to alter */ 5522 int top, int left); /* new upper-left corner */</pre> 5523 <p>As usual, the changed position can be queried with 5524 field_infor().</p> 5525 </div> 5526 5527 <div class="SECT3"> 5528 <hr> 5529 5530 <h4 class="SECT3"><a name="JUSTIFYFIELD" id= 5531 "JUSTIFYFIELD">18.3.3. Field Justification</a></h4> 5532 5533 <p>The justification to be done for the field can be 5534 fixed using the function set_field_just().</p> 5535 5536 <pre class= 5537 "PROGRAMLISTING"> int set_field_just(FIELD *field, /* field to alter */ 5538 int justmode); /* mode to set */ 5539 int field_just(FIELD *field); /* fetch justify mode of field */</pre> 5540 <p>The justification mode valued accepted and returned by 5541 these functions are NO_JUSTIFICATION, JUSTIFY_RIGHT, 5542 JUSTIFY_LEFT, or JUSTIFY_CENTER.</p> 5543 </div> 5544 5545 <div class="SECT3"> 5546 <hr> 5547 5548 <h4 class="SECT3"><a name="FIELDDISPATTRIB" id= 5549 "FIELDDISPATTRIB">18.3.4. Field Display Attributes</a></h4> 5550 5551 <p>As you have seen, in the above example, display 5552 attribute for the fields can be set with set_field_fore() 5553 and setfield_back(). These functions set foreground and 5554 background attribute of the fields. You can also specify 5555 a pad character which will be filled in the unfilled 5556 portion of the field. The pad character is set with a 5557 call to set_field_pad(). Default pad value is a space. 5558 The functions field_fore(), field_back, field_pad() can 5559 be used to query the present foreground, background 5560 attributes and pad character for the field. The following 5561 list gives the usage of functions.</p> 5562 5563 <pre class= 5564 "PROGRAMLISTING"> int set_field_fore(FIELD *field, /* field to alter */ 5565 chtype attr); /* attribute to set */ 5566 5567chtype field_fore(FIELD *field); /* field to query */ 5568 /* returns foreground attribute */ 5569 5570int set_field_back(FIELD *field, /* field to alter */ 5571 chtype attr); /* attribute to set */ 5572 5573chtype field_back(FIELD *field); /* field to query */ 5574 /* returns background attribute */ 5575 5576int set_field_pad(FIELD *field, /* field to alter */ 5577 int pad); /* pad character to set */ 5578 5579chtype field_pad(FIELD *field); /* field to query */ 5580 /* returns present pad character */ </pre> 5581 <p>Though above functions seem quite simple, using colors 5582 with set_field_fore() may be frustrating in the 5583 beginning. Let me first explain about foreground and 5584 background attributes of a field. The foreground 5585 attribute is associated with the character. That means a 5586 character in the field is printed with the attribute you 5587 have set with set_field_fore(). Background attribute is 5588 the attribute used to fill background of field, whether 5589 any character is there or not. So what about colors? 5590 Since colors are always defined in pairs, what is the 5591 right way to display colored fields? Here's an example 5592 clarifying color attributes.</p> 5593 5594 <div class="EXAMPLE"> 5595 <a name="FFOAT" id="FFOAT"></a> 5596 <p><b>Example 26. Form Attributes example</b> 5597 </p> 5598 5599 <pre class="PROGRAMLISTING"><span class= 5600 "INLINEMEDIAOBJECT">#include <form.h> 5601 5602int main() 5603{ FIELD *field[3]; 5604 FORM *my_form; 5605 int ch; 5606 5607 /* Initialize curses */ 5608 initscr(); 5609 start_color(); 5610 cbreak(); 5611 noecho(); 5612 keypad(stdscr, TRUE); 5613 5614 /* Initialize few color pairs */ 5615 init_pair(1, COLOR_WHITE, COLOR_BLUE); 5616 init_pair(2, COLOR_WHITE, COLOR_BLUE); 5617 5618 /* Initialize the fields */ 5619 field[0] = new_field(1, 10, 4, 18, 0, 0); 5620 field[1] = new_field(1, 10, 6, 18, 0, 0); 5621 field[2] = NULL; 5622 5623 /* Set field options */ 5624 set_field_fore(field[0], COLOR_PAIR(1));/* Put the field with blue background */ 5625 set_field_back(field[0], COLOR_PAIR(2));/* and white foreground (characters */ 5626 /* are printed in white */ 5627 field_opts_off(field[0], O_AUTOSKIP); /* Don't go to next field when this */ 5628 /* Field is filled up */ 5629 set_field_back(field[1], A_UNDERLINE); 5630 field_opts_off(field[1], O_AUTOSKIP); 5631 5632 /* Create the form and post it */ 5633 my_form = new_form(field); 5634 post_form(my_form); 5635 refresh(); 5636 5637 set_current_field(my_form, field[0]); /* Set focus to the colored field */ 5638 mvprintw(4, 10, "Value 1:"); 5639 mvprintw(6, 10, "Value 2:"); 5640 mvprintw(LINES - 2, 0, "Use UP, DOWN arrow keys to switch between fields"); 5641 refresh(); 5642 5643 /* Loop through to get user requests */ 5644 while((ch = getch()) != KEY_F(1)) 5645 { switch(ch) 5646 { case KEY_DOWN: 5647 /* Go to next field */ 5648 form_driver(my_form, REQ_NEXT_FIELD); 5649 /* Go to the end of the present buffer */ 5650 /* Leaves nicely at the last character */ 5651 form_driver(my_form, REQ_END_LINE); 5652 break; 5653 case KEY_UP: 5654 /* Go to previous field */ 5655 form_driver(my_form, REQ_PREV_FIELD); 5656 form_driver(my_form, REQ_END_LINE); 5657 break; 5658 default: 5659 /* If this is a normal character, it gets */ 5660 /* Printed */ 5661 form_driver(my_form, ch); 5662 break; 5663 } 5664 } 5665 5666 /* Un post form and free the memory */ 5667 unpost_form(my_form); 5668 free_form(my_form); 5669 free_field(field[0]); 5670 free_field(field[1]); 5671 5672 endwin(); 5673 return 0; 5674}</span></pre> 5675 </div> 5676 5677 <p>Play with the color pairs and try to understand the 5678 foreground and background attributes. In my programs 5679 using color attributes, I usually set only the background 5680 with set_field_back(). Curses simply doesn't allow 5681 defining individual color attributes.</p> 5682 </div> 5683 5684 <div class="SECT3"> 5685 <hr> 5686 5687 <h4 class="SECT3"><a name="FIELDOPTIONBITS" id= 5688 "FIELDOPTIONBITS">18.3.5. Field Option Bits</a></h4> 5689 5690 <p>There is also a large collection of field option bits 5691 you can set to control various aspects of forms 5692 processing. You can manipulate them with these 5693 functions:</p> 5694 5695 <pre class= 5696 "PROGRAMLISTING">int set_field_opts(FIELD *field, /* field to alter */ 5697 int attr); /* attribute to set */ 5698 5699int field_opts_on(FIELD *field, /* field to alter */ 5700 int attr); /* attributes to turn on */ 5701 5702int field_opts_off(FIELD *field, /* field to alter */ 5703 int attr); /* attributes to turn off */ 5704 5705int field_opts(FIELD *field); /* field to query */ </pre> 5706 <p>The function set_field_opts() can be used to directly 5707 set attributes of a field or you can choose to switch a 5708 few attributes on and off with field_opts_on() and 5709 field_opts_off() selectively. Anytime you can query the 5710 attributes of a field with field_opts(). The following is 5711 the list of available options. By default, all options 5712 are on.</p> 5713 5714 <div class="VARIABLELIST"> 5715 <dl> 5716 <dt>O_VISIBLE</dt> 5717 5718 <dd> 5719 <p>Controls whether the field is visible on the 5720 screen. Can be used during form processing to hide 5721 or pop up fields depending on the value of parent 5722 fields.</p> 5723 </dd> 5724 5725 <dt>O_ACTIVE</dt> 5726 5727 <dd> 5728 <p>Controls whether the field is active during 5729 forms processing (i.e. visited by form navigation 5730 keys). Can be used to make labels or derived fields 5731 with buffer values alterable by the forms 5732 application, not the user.</p> 5733 </dd> 5734 5735 <dt>O_PUBLIC</dt> 5736 5737 <dd> 5738 <p>Controls whether data is displayed during field 5739 entry. If this option is turned off on a field, the 5740 library will accept and edit data in that field, 5741 but it will not be displayed and the visible field 5742 cursor will not move. You can turn off the O_PUBLIC 5743 bit to define password fields.</p> 5744 </dd> 5745 5746 <dt>O_EDIT</dt> 5747 5748 <dd> 5749 <p>Controls whether the field's data can be 5750 modified. When this option is off, all editing 5751 requests except <tt class= 5752 "LITERAL">REQ_PREV_CHOICE</tt> and <tt class= 5753 "LITERAL">REQ_NEXT_CHOICE</tt>will fail. Such 5754 read-only fields may be useful for help 5755 messages.</p> 5756 </dd> 5757 5758 <dt>O_WRAP</dt> 5759 5760 <dd> 5761 <p>Controls word-wrapping in multi-line fields. 5762 Normally, when any character of a (blank-separated) 5763 word reaches the end of the current line, the 5764 entire word is wrapped to the next line (assuming 5765 there is one). When this option is off, the word 5766 will be split across the line break.</p> 5767 </dd> 5768 5769 <dt>O_BLANK</dt> 5770 5771 <dd> 5772 <p>Controls field blanking. When this option is on, 5773 entering a character at the first field position 5774 erases the entire field (except for the 5775 just-entered character).</p> 5776 </dd> 5777 5778 <dt>O_AUTOSKIP</dt> 5779 5780 <dd> 5781 <p>Controls automatic skip to next field when this 5782 one fills. Normally, when the forms user tries to 5783 type more data into a field than will fit, the 5784 editing location jumps to next field. When this 5785 option is off, the user's cursor will hang at the 5786 end of the field. This option is ignored in dynamic 5787 fields that have not reached their size limit.</p> 5788 </dd> 5789 5790 <dt>O_NULLOK</dt> 5791 5792 <dd> 5793 <p>Controls whether validation is applied to blank 5794 fields. Normally, it is not; the user can leave a 5795 field blank without invoking the usual validation 5796 check on exit. If this option is off on a field, 5797 exit from it will invoke a validation check.</p> 5798 </dd> 5799 5800 <dt>O_PASSOK</dt> 5801 5802 <dd> 5803 <p>Controls whether validation occurs on every 5804 exit, or only after the field is modified. Normally 5805 the latter is true. Setting O_PASSOK may be useful 5806 if your field's validation function may change 5807 during forms processing.</p> 5808 </dd> 5809 5810 <dt>O_STATIC</dt> 5811 5812 <dd> 5813 <p>Controls whether the field is fixed to its 5814 initial dimensions. If you turn this off, the field 5815 becomes dynamic and will stretch to fit entered 5816 data.</p> 5817 </dd> 5818 </dl> 5819 </div> 5820 5821 <p>A field's options cannot be changed while the field is 5822 currently selected. However, options may be changed on 5823 posted fields that are not current.</p> 5824 5825 <p>The option values are bit-masks and can be composed 5826 with logical-or in the obvious way. You have seen the 5827 usage of switching off O_AUTOSKIP option. The following 5828 example clarifies usage of some more options. Other 5829 options are explained where appropriate.</p> 5830 5831 <div class="EXAMPLE"> 5832 <a name="FFOOP" id="FFOOP"></a> 5833 <p><b>Example 27. Field Options Usage example</b> 5834 </p> 5835 5836 <pre class="PROGRAMLISTING"><span class= 5837 "INLINEMEDIAOBJECT">#include <form.h> 5838 5839#define STARTX 15 5840#define STARTY 4 5841#define WIDTH 25 5842 5843#define N_FIELDS 3 5844 5845int main() 5846{ FIELD *field[N_FIELDS]; 5847 FORM *my_form; 5848 int ch, i; 5849 5850 /* Initialize curses */ 5851 initscr(); 5852 cbreak(); 5853 noecho(); 5854 keypad(stdscr, TRUE); 5855 5856 /* Initialize the fields */ 5857 for(i = 0; i < N_FIELDS - 1; ++i) 5858 field[i] = new_field(1, WIDTH, STARTY + i * 2, STARTX, 0, 0); 5859 field[N_FIELDS - 1] = NULL; 5860 5861 /* Set field options */ 5862 set_field_back(field[1], A_UNDERLINE); /* Print a line for the option */ 5863 5864 field_opts_off(field[0], O_ACTIVE); /* This field is a static label */ 5865 field_opts_off(field[1], O_PUBLIC); /* This filed is like a password field*/ 5866 field_opts_off(field[1], O_AUTOSKIP); /* To avoid entering the same field */ 5867 /* after last character is entered */ 5868 5869 /* Create the form and post it */ 5870 my_form = new_form(field); 5871 post_form(my_form); 5872 refresh(); 5873 5874 set_field_just(field[0], JUSTIFY_CENTER); /* Center Justification */ 5875 set_field_buffer(field[0], 0, "This is a static Field"); 5876 /* Initialize the field */ 5877 mvprintw(STARTY, STARTX - 10, "Field 1:"); 5878 mvprintw(STARTY + 2, STARTX - 10, "Field 2:"); 5879 refresh(); 5880 5881 /* Loop through to get user requests */ 5882 while((ch = getch()) != KEY_F(1)) 5883 { switch(ch) 5884 { case KEY_DOWN: 5885 /* Go to next field */ 5886 form_driver(my_form, REQ_NEXT_FIELD); 5887 /* Go to the end of the present buffer */ 5888 /* Leaves nicely at the last character */ 5889 form_driver(my_form, REQ_END_LINE); 5890 break; 5891 case KEY_UP: 5892 /* Go to previous field */ 5893 form_driver(my_form, REQ_PREV_FIELD); 5894 form_driver(my_form, REQ_END_LINE); 5895 break; 5896 default: 5897 /* If this is a normal character, it gets */ 5898 /* Printed */ 5899 form_driver(my_form, ch); 5900 break; 5901 } 5902 } 5903 5904 /* Un post form and free the memory */ 5905 unpost_form(my_form); 5906 free_form(my_form); 5907 free_field(field[0]); 5908 free_field(field[1]); 5909 5910 endwin(); 5911 return 0; 5912}</span></pre> 5913 </div> 5914 5915 <p>This example, though useless, shows the usage of 5916 options. If used properly, they can present information 5917 very effectively in a form. The second field being not 5918 O_PUBLIC, does not show the characters you are 5919 typing.</p> 5920 </div> 5921 5922 <div class="SECT3"> 5923 <hr> 5924 5925 <h4 class="SECT3"><a name="FIELDSTATUS" id= 5926 "FIELDSTATUS">18.3.6. Field Status</a></h4> 5927 5928 <p>The field status specifies whether the field has got 5929 edited or not. It is initially set to FALSE and when user 5930 enters something and the data buffer gets modified it 5931 becomes TRUE. So a field's status can be queried to find 5932 out whether it has been modified or not. The following 5933 functions can assist in those operations.</p> 5934 5935 <pre class= 5936 "PROGRAMLISTING">int set_field_status(FIELD *field, /* field to alter */ 5937 int status); /* status to set */ 5938 5939int field_status(FIELD *field); /* fetch status of field */</pre> 5940 <p>It is better to check the field's status only after 5941 after leaving the field, as data buffer might not have 5942 been updated yet as the validation is still due. To 5943 guarantee that right status is returned, call 5944 field_status() either (1) in the field's exit validation 5945 check routine, (2) from the field's or form's 5946 initialization or termination hooks, or (3) just after a 5947 REQ_VALIDATION request has been processed by the forms 5948 driver</p> 5949 </div> 5950 5951 <div class="SECT3"> 5952 <hr> 5953 5954 <h4 class="SECT3"><a name="FIELDUSERPTR" id= 5955 "FIELDUSERPTR">18.3.7. Field User Pointer</a></h4> 5956 5957 <p>Every field structure contains one pointer that can be 5958 used by the user for various purposes. It is not touched 5959 by forms library and can be used for any purpose by the 5960 user. The following functions set and fetch user 5961 pointer.</p> 5962 5963 <pre class= 5964 "PROGRAMLISTING">int set_field_userptr(FIELD *field, 5965 char *userptr); /* the user pointer you wish to associate */ 5966 /* with the field */ 5967 5968char *field_userptr(FIELD *field); /* fetch user pointer of the field */</pre> 5969 </div> 5970 5971 <div class="SECT3"> 5972 <hr> 5973 5974 <h4 class="SECT3"><a name="VARIABLESIZEFIELDS" id= 5975 "VARIABLESIZEFIELDS">18.3.8. Variable-Sized Fields</a></h4> 5976 5977 <p>If you want a dynamically changing field with variable 5978 width, this is the feature you want to put to full use. 5979 This will allow the user to enter more data than the 5980 original size of the field and let the field grow. 5981 According to the field orientation it will scroll 5982 horizontally or vertically to incorporate the new 5983 data.</p> 5984 5985 <p>To make a field dynamically growable, the option 5986 O_STATIC should be turned off. This can be done with 5987 a</p> 5988 5989 <pre class= 5990 "PROGRAMLISTING"> field_opts_off(field_pointer, O_STATIC);</pre> 5991 <p>But it is usually not advisable to allow a field to 5992 grow infinitely. You can set a maximum limit to the 5993 growth of the field with</p> 5994 5995 <pre class= 5996 "PROGRAMLISTING">int set_max_field(FIELD *field, /* Field on which to operate */ 5997 int max_growth); /* maximum growth allowed for the field */</pre> 5998 <p>The field info for a dynamically growable field can be 5999 retrieved by</p> 6000 6001 <pre class= 6002 "PROGRAMLISTING">int dynamic_field_info( FIELD *field, /* Field on which to operate */ 6003 int *prows, /* number of rows will be filled in this */ 6004 int *pcols, /* number of columns will be filled in this*/ 6005 int *pmax) /* maximum allowable growth will be filled */ 6006 /* in this */</pre>Though field_info 6007work as usual, it is advisable to use this function to get the 6008proper attributes of a dynamically growable field. 6009 <p>Recall the library routine new_field; a new field 6010 created with height set to one will be defined to be a 6011 one line field. A new field created with height greater 6012 than one will be defined to be a multi line field.</p> 6013 6014 <p>A one line field with O_STATIC turned off (dynamically 6015 growable field) will contain a single fixed row, but the 6016 number of columns can increase if the user enters more 6017 data than the initial field will hold. The number of 6018 columns displayed will remain fixed and the additional 6019 data will scroll horizontally.</p> 6020 6021 <p>A multi line field with O_STATIC turned off 6022 (dynamically growable field) will contain a fixed number 6023 of columns, but the number of rows can increase if the 6024 user enters more data than the initial field will hold. 6025 The number of rows displayed will remain fixed and the 6026 additional data will scroll vertically.</p> 6027 6028 <p>The above two paragraphs pretty much describe a 6029 dynamically growable field's behavior. The way other 6030 parts of forms library behaves is described below:</p> 6031 6032 <ol type="1"> 6033 <li> 6034 <p>The field option O_AUTOSKIP will be ignored if the 6035 option O_STATIC is off and there is no maximum growth 6036 specified for the field. Currently, O_AUTOSKIP 6037 generates an automatic REQ_NEXT_FIELD form driver 6038 request when the user types in the last character 6039 position of a field. On a growable field with no 6040 maximum growth specified, there is no last character 6041 position. If a maximum growth is specified, the 6042 O_AUTOSKIP option will work as normal if the field 6043 has grown to its maximum size.</p> 6044 </li> 6045 6046 <li> 6047 <p>The field justification will be ignored if the 6048 option O_STATIC is off. Currently, set_field_just can 6049 be used to JUSTIFY_LEFT, JUSTIFY_RIGHT, 6050 JUSTIFY_CENTER the contents of a one line field. A 6051 growable one line field will, by definition, grow and 6052 scroll horizontally and may contain more data than 6053 can be justified. The return from field_just will be 6054 unchanged.</p> 6055 </li> 6056 6057 <li> 6058 <p>The overloaded form driver request REQ_NEW_LINE 6059 will operate the same way regardless of the 6060 O_NL_OVERLOAD form option if the field option 6061 O_STATIC is off and there is no maximum growth 6062 specified for the field. Currently, if the form 6063 option O_NL_OVERLOAD is on, REQ_NEW_LINE implicitly 6064 generates a REQ_NEXT_FIELD if called from the last 6065 line of a field. If a field can grow without bound, 6066 there is no last line, so REQ_NEW_LINE will never 6067 implicitly generate a REQ_NEXT_FIELD. If a maximum 6068 growth limit is specified and the O_NL_OVERLOAD form 6069 option is on, REQ_NEW_LINE will only implicitly 6070 generate REQ_NEXT_FIELD if the field has grown to its 6071 maximum size and the user is on the last line.</p> 6072 </li> 6073 6074 <li> 6075 <p>The library call dup_field will work as usual; it 6076 will duplicate the field, including the current 6077 buffer size and contents of the field being 6078 duplicated. Any specified maximum growth will also be 6079 duplicated.</p> 6080 </li> 6081 6082 <li> 6083 <p>The library call link_field will work as usual; it 6084 will duplicate all field attributes and share buffers 6085 with the field being linked. If the O_STATIC field 6086 option is subsequently changed by a field sharing 6087 buffers, how the system reacts to an attempt to enter 6088 more data into the field than the buffer will 6089 currently hold will depend on the setting of the 6090 option in the current field.</p> 6091 </li> 6092 6093 <li> 6094 <p>The library call field_info will work as usual; 6095 the variable nrow will contain the value of the 6096 original call to new_field. The user should use 6097 dynamic_field_info, described above, to query the 6098 current size of the buffer.</p> 6099 </li> 6100 </ol> 6101 6102 <p>Some of the above points make sense only after 6103 explaining form driver. We will be looking into that in 6104 next few sections.</p> 6105 </div> 6106 </div> 6107 6108 <div class="SECT2"> 6109 <hr> 6110 6111 <h3 class="SECT2"><a name="FORMWINDOWS" id= 6112 "FORMWINDOWS">18.4. Form Windows</a></h3> 6113 6114 <p>The form windows concept is pretty much similar to menu 6115 windows. Every form is associated with a main window and a 6116 sub window. The form main window displays any title or 6117 border associated or whatever the user wishes. Then the sub 6118 window contains all the fields and displays them according 6119 to their position. This gives the flexibility of 6120 manipulating fancy form displaying very easily.</p> 6121 6122 <p>Since this is pretty much similar to menu windows, I am 6123 providing an example with out much explanation. The 6124 functions are similar and they work the same way.</p> 6125 6126 <div class="EXAMPLE"> 6127 <a name="FFOWI" id="FFOWI"></a> 6128 <p><b>Example 28. Form Windows Example</b> 6129 </p> 6130 6131 <pre class="PROGRAMLISTING"><span class= 6132 "INLINEMEDIAOBJECT">#include <string.h> 6133#include <form.h> 6134 6135void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color); 6136 6137int main() 6138{ 6139 FIELD *field[3]; 6140 FORM *my_form; 6141 WINDOW *my_form_win; 6142 int ch, rows, cols; 6143 6144 /* Initialize curses */ 6145 initscr(); 6146 start_color(); 6147 cbreak(); 6148 noecho(); 6149 keypad(stdscr, TRUE); 6150 6151 /* Initialize few color pairs */ 6152 init_pair(1, COLOR_RED, COLOR_BLACK); 6153 6154 /* Initialize the fields */ 6155 field[0] = new_field(1, 10, 6, 1, 0, 0); 6156 field[1] = new_field(1, 10, 8, 1, 0, 0); 6157 field[2] = NULL; 6158 6159 /* Set field options */ 6160 set_field_back(field[0], A_UNDERLINE); 6161 field_opts_off(field[0], O_AUTOSKIP); /* Don't go to next field when this */ 6162 /* Field is filled up */ 6163 set_field_back(field[1], A_UNDERLINE); 6164 field_opts_off(field[1], O_AUTOSKIP); 6165 6166 /* Create the form and post it */ 6167 my_form = new_form(field); 6168 6169 /* Calculate the area required for the form */ 6170 scale_form(my_form, &rows, &cols); 6171 6172 /* Create the window to be associated with the form */ 6173 my_form_win = newwin(rows + 4, cols + 4, 4, 4); 6174 keypad(my_form_win, TRUE); 6175 6176 /* Set main window and sub window */ 6177 set_form_win(my_form, my_form_win); 6178 set_form_sub(my_form, derwin(my_form_win, rows, cols, 2, 2)); 6179 6180 /* Print a border around the main window and print a title */ 6181 box(my_form_win, 0, 0); 6182 print_in_middle(my_form_win, 1, 0, cols + 4, "My Form", COLOR_PAIR(1)); 6183 6184 post_form(my_form); 6185 wrefresh(my_form_win); 6186 6187 mvprintw(LINES - 2, 0, "Use UP, DOWN arrow keys to switch between fields"); 6188 refresh(); 6189 6190 /* Loop through to get user requests */ 6191 while((ch = wgetch(my_form_win)) != KEY_F(1)) 6192 { switch(ch) 6193 { case KEY_DOWN: 6194 /* Go to next field */ 6195 form_driver(my_form, REQ_NEXT_FIELD); 6196 /* Go to the end of the present buffer */ 6197 /* Leaves nicely at the last character */ 6198 form_driver(my_form, REQ_END_LINE); 6199 break; 6200 case KEY_UP: 6201 /* Go to previous field */ 6202 form_driver(my_form, REQ_PREV_FIELD); 6203 form_driver(my_form, REQ_END_LINE); 6204 break; 6205 default: 6206 /* If this is a normal character, it gets */ 6207 /* Printed */ 6208 form_driver(my_form, ch); 6209 break; 6210 } 6211 } 6212 6213 /* Un post form and free the memory */ 6214 unpost_form(my_form); 6215 free_form(my_form); 6216 free_field(field[0]); 6217 free_field(field[1]); 6218 6219 endwin(); 6220 return 0; 6221} 6222 6223void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color) 6224{ int length, x, y; 6225 float temp; 6226 6227 if(win == NULL) 6228 win = stdscr; 6229 getyx(win, y, x); 6230 if(startx != 0) 6231 x = startx; 6232 if(starty != 0) 6233 y = starty; 6234 if(width == 0) 6235 width = 80; 6236 6237 length = strlen(string); 6238 temp = (width - length)/ 2; 6239 x = startx + (int)temp; 6240 wattron(win, color); 6241 mvwprintw(win, y, x, "%s", string); 6242 wattroff(win, color); 6243 refresh(); 6244}</span></pre> 6245 </div> 6246 </div> 6247 6248 <div class="SECT2"> 6249 <hr> 6250 6251 <h3 class="SECT2"><a name="FILEDVALIDATE" id= 6252 "FILEDVALIDATE">18.5. Field Validation</a></h3> 6253 6254 <p>By default, a field will accept any data input by the 6255 user. It is possible to attach validation to the field. 6256 Then any attempt by the user to leave the field, while it 6257 contains data that doesn't match the validation type will 6258 fail. Some validation types also have a character-validity 6259 check for each time a character is entered in the 6260 field.</p> 6261 6262 <p>Validation can be attached to a field with the following 6263 function.</p> 6264 6265 <pre class= 6266 "PROGRAMLISTING">int set_field_type(FIELD *field, /* field to alter */ 6267 FIELDTYPE *ftype, /* type to associate */ 6268 ...); /* additional arguments*/</pre>Once 6269set, the validation type for a field can be queried with 6270 6271 <pre class= 6272 "PROGRAMLISTING">FIELDTYPE *field_type(FIELD *field); /* field to query */</pre> 6273 <p>The form driver validates the data in a field only when 6274 data is entered by the end-user. Validation does not occur 6275 when</p> 6276 6277 <ul> 6278 <li> 6279 <p>the application program changes the field value by 6280 calling set_field_buffer.</p> 6281 </li> 6282 6283 <li> 6284 <p>linked field values are changed indirectly -- by 6285 changing the field to which they are linked</p> 6286 </li> 6287 </ul> 6288 6289 <p>The following are the pre-defined validation types. You 6290 can also specify custom validation, though it is a bit 6291 tricky and cumbersome.</p> 6292 6293 <h1 class="BRIDGEHEAD"><a name="AEN1074" id= 6294 "AEN1074"></a>TYPE_ALPHA</h1> 6295 6296 <p>This field type accepts alphabetic data; no blanks, no 6297 digits, no special characters (this is checked at 6298 character-entry time). It is set up with:</p> 6299 6300 <pre class= 6301 "PROGRAMLISTING">int set_field_type(FIELD *field, /* field to alter */ 6302 TYPE_ALPHA, /* type to associate */ 6303 int width); /* minimum width of field */</pre> 6304 <p>The width argument sets a minimum width of data. The 6305 user has to enter at-least width number of characters 6306 before he can leave the field. Typically you'll want to set 6307 this to the field width; if it is greater than the field 6308 width, the validation check will always fail. A minimum 6309 width of zero makes field completion optional.</p> 6310 6311 <h1 class="BRIDGEHEAD"><a name="AEN1078" id= 6312 "AEN1078"></a>TYPE_ALNUM</h1> 6313 6314 <p>This field type accepts alphabetic data and digits; no 6315 blanks, no special characters (this is checked at 6316 character-entry time). It is set up with:</p> 6317 6318 <pre class= 6319 "PROGRAMLISTING">int set_field_type(FIELD *field, /* field to alter */ 6320 TYPE_ALNUM, /* type to associate */ 6321 int width); /* minimum width of field */</pre> 6322 <p>The width argument sets a minimum width of data. As with 6323 TYPE_ALPHA, typically you'll want to set this to the field 6324 width; if it is greater than the field width, the 6325 validation check will always fail. A minimum width of zero 6326 makes field completion optional.</p> 6327 6328 <h1 class="BRIDGEHEAD"><a name="AEN1082" id= 6329 "AEN1082"></a>TYPE_ENUM</h1> 6330 6331 <p>This type allows you to restrict a field's values to be 6332 among a specified set of string values (for example, the 6333 two-letter postal codes for U.S. states). It is set up 6334 with:</p> 6335 6336 <pre class= 6337 "PROGRAMLISTING">int set_field_type(FIELD *field, /* field to alter */ 6338 TYPE_ENUM, /* type to associate */ 6339 char **valuelist; /* list of possible values */ 6340 int checkcase; /* case-sensitive? */ 6341 int checkunique); /* must specify uniquely? */</pre> 6342 <p>The valuelist parameter must point at a NULL-terminated 6343 list of valid strings. The checkcase argument, if true, 6344 makes comparison with the string case-sensitive.</p> 6345 6346 <p>When the user exits a TYPE_ENUM field, the validation 6347 procedure tries to complete the data in the buffer to a 6348 valid entry. If a complete choice string has been entered, 6349 it is of course valid. But it is also possible to enter a 6350 prefix of a valid string and have it completed for you.</p> 6351 6352 <p>By default, if you enter such a prefix and it matches 6353 more than one value in the string list, the prefix will be 6354 completed to the first matching value. But the checkunique 6355 argument, if true, requires prefix matches to be unique in 6356 order to be valid.</p> 6357 6358 <p>The REQ_NEXT_CHOICE and REQ_PREV_CHOICE input requests 6359 can be particularly useful with these fields.</p> 6360 6361 <h1 class="BRIDGEHEAD"><a name="AEN1089" id= 6362 "AEN1089"></a>TYPE_INTEGER</h1> 6363 6364 <p>This field type accepts an integer. It is set up as 6365 follows:</p> 6366 6367 <pre class= 6368 "PROGRAMLISTING">int set_field_type(FIELD *field, /* field to alter */ 6369 TYPE_INTEGER, /* type to associate */ 6370 int padding, /* # places to zero-pad to */ 6371 int vmin, int vmax); /* valid range */</pre> 6372 <p>Valid characters consist of an optional leading minus 6373 and digits. The range check is performed on exit. If the 6374 range maximum is less than or equal to the minimum, the 6375 range is ignored.</p> 6376 6377 <p>If the value passes its range check, it is padded with 6378 as many leading zero digits as necessary to meet the 6379 padding argument.</p> 6380 6381 <p>A TYPE_INTEGER value buffer can conveniently be 6382 interpreted with the C library function atoi(3).</p> 6383 6384 <h1 class="BRIDGEHEAD"><a name="AEN1095" id= 6385 "AEN1095"></a>TYPE_NUMERIC</h1> 6386 6387 <p>This field type accepts a decimal number. It is set up 6388 as follows:</p> 6389 6390 <pre class= 6391 "PROGRAMLISTING">int set_field_type(FIELD *field, /* field to alter */ 6392 TYPE_NUMERIC, /* type to associate */ 6393 int padding, /* # places of precision */ 6394 int vmin, int vmax); /* valid range */</pre> 6395 <p>Valid characters consist of an optional leading minus 6396 and digits. possibly including a decimal point. The range 6397 check is performed on exit. If the range maximum is less 6398 than or equal to the minimum, the range is ignored.</p> 6399 6400 <p>If the value passes its range check, it is padded with 6401 as many trailing zero digits as necessary to meet the 6402 padding argument.</p> 6403 6404 <p>A TYPE_NUMERIC value buffer can conveniently be 6405 interpreted with the C library function atof(3).</p> 6406 6407 <h1 class="BRIDGEHEAD"><a name="AEN1101" id= 6408 "AEN1101"></a>TYPE_REGEXP</h1> 6409 6410 <p>This field type accepts data matching a regular 6411 expression. It is set up as follows:</p> 6412 6413 <pre class= 6414 "PROGRAMLISTING">int set_field_type(FIELD *field, /* field to alter */ 6415 TYPE_REGEXP, /* type to associate */ 6416 char *regexp); /* expression to match */</pre> 6417 <p>The syntax for regular expressions is that of 6418 regcomp(3). The check for regular-expression match is 6419 performed on exit.</p> 6420 </div> 6421 6422 <div class="SECT2"> 6423 <hr> 6424 6425 <h3 class="SECT2"><a name="FORMDRIVER" id= 6426 "FORMDRIVER">18.6. Form Driver: The work horse of the forms 6427 system</a></h3> 6428 6429 <p>As in the menu system, form_driver() plays a very 6430 important role in forms system. All types of requests to 6431 forms system should be funneled through form_driver().</p> 6432 6433 <pre class= 6434 "PROGRAMLISTING">int form_driver(FORM *form, /* form on which to operate */ 6435 int request) /* form request code */</pre> 6436 <p>As you have seen some of the examples above, you have to 6437 be in a loop looking for user input and then decide whether 6438 it is a field data or a form request. The form requests are 6439 then passed to form_driver() to do the work.</p> 6440 6441 <p>The requests roughly can be divided into following 6442 categories. Different requests and their usage is explained 6443 below:</p> 6444 6445 <div class="SECT3"> 6446 <hr> 6447 6448 <h4 class="SECT3"><a name="PAGENAVREQ" id= 6449 "PAGENAVREQ">18.6.1. Page Navigation Requests</a></h4> 6450 6451 <p>These requests cause page-level moves through the 6452 form, triggering display of a new form screen. A form can 6453 be made of multiple pages. If you have a big form with 6454 lot of fields and logical sections, then you can divide 6455 the form into pages. The function set_new_page() to set a 6456 new page at the field specified.</p> 6457 6458 <pre class= 6459 "PROGRAMLISTING">int set_new_page(FIELD *field,/* Field at which page break to be set or unset */ 6460 bool new_page_flag); /* should be TRUE to put a break */</pre> 6461 <p>The following requests allow you to move to different 6462 pages</p> 6463 6464 <ul> 6465 <li> 6466 <p><span class="emphasis"><i class= 6467 "EMPHASIS">REQ_NEXT_PAGE</i></span> Move to the next 6468 form page.</p> 6469 </li> 6470 6471 <li> 6472 <p><span class="emphasis"><i class= 6473 "EMPHASIS">REQ_PREV_PAGE</i></span> Move to the 6474 previous form page.</p> 6475 </li> 6476 6477 <li> 6478 <p><span class="emphasis"><i class= 6479 "EMPHASIS">REQ_FIRST_PAGE</i></span> Move to the 6480 first form page.</p> 6481 </li> 6482 6483 <li> 6484 <p><span class="emphasis"><i class= 6485 "EMPHASIS">REQ_LAST_PAGE</i></span> Move to the last 6486 form page.</p> 6487 </li> 6488 </ul> 6489 6490 <p>These requests treat the list as cyclic; that is, 6491 REQ_NEXT_PAGE from the last page goes to the first, and 6492 REQ_PREV_PAGE from the first page goes to the last.</p> 6493 </div> 6494 6495 <div class="SECT3"> 6496 <hr> 6497 6498 <h4 class="SECT3"><a name="INTERFIELDNAVREQ" id= 6499 "INTERFIELDNAVREQ">18.6.2. Inter-Field Navigation 6500 Requests</a></h4> 6501 6502 <p>These requests handle navigation between fields on the 6503 same page.</p> 6504 6505 <ul> 6506 <li> 6507 <p><span class="emphasis"><i class= 6508 "EMPHASIS">REQ_NEXT_FIELD</i></span> Move to next 6509 field.</p> 6510 </li> 6511 6512 <li> 6513 <p><span class="emphasis"><i class= 6514 "EMPHASIS">REQ_PREV_FIELD</i></span> Move to previous 6515 field.</p> 6516 </li> 6517 6518 <li> 6519 <p><span class="emphasis"><i class= 6520 "EMPHASIS">REQ_FIRST_FIELD</i></span> Move to the 6521 first field.</p> 6522 </li> 6523 6524 <li> 6525 <p><span class="emphasis"><i class= 6526 "EMPHASIS">REQ_LAST_FIELD</i></span> Move to the last 6527 field.</p> 6528 </li> 6529 6530 <li> 6531 <p><span class="emphasis"><i class= 6532 "EMPHASIS">REQ_SNEXT_FIELD</i></span> Move to sorted 6533 next field.</p> 6534 </li> 6535 6536 <li> 6537 <p><span class="emphasis"><i class= 6538 "EMPHASIS">REQ_SPREV_FIELD</i></span> Move to sorted 6539 previous field.</p> 6540 </li> 6541 6542 <li> 6543 <p><span class="emphasis"><i class= 6544 "EMPHASIS">REQ_SFIRST_FIELD</i></span> Move to the 6545 sorted first field.</p> 6546 </li> 6547 6548 <li> 6549 <p><span class="emphasis"><i class= 6550 "EMPHASIS">REQ_SLAST_FIELD</i></span> Move to the 6551 sorted last field.</p> 6552 </li> 6553 6554 <li> 6555 <p><span class="emphasis"><i class= 6556 "EMPHASIS">REQ_LEFT_FIELD</i></span> Move left to 6557 field.</p> 6558 </li> 6559 6560 <li> 6561 <p><span class="emphasis"><i class= 6562 "EMPHASIS">REQ_RIGHT_FIELD</i></span> Move right to 6563 field.</p> 6564 </li> 6565 6566 <li> 6567 <p><span class="emphasis"><i class= 6568 "EMPHASIS">REQ_UP_FIELD</i></span> Move up to 6569 field.</p> 6570 </li> 6571 6572 <li> 6573 <p><span class="emphasis"><i class= 6574 "EMPHASIS">REQ_DOWN_FIELD</i></span> Move down to 6575 field.</p> 6576 </li> 6577 </ul> 6578 6579 <p>These requests treat the list of fields on a page as 6580 cyclic; that is, REQ_NEXT_FIELD from the last field goes 6581 to the first, and REQ_PREV_FIELD from the first field 6582 goes to the last. The order of the fields for these (and 6583 the REQ_FIRST_FIELD and REQ_LAST_FIELD requests) is 6584 simply the order of the field pointers in the form array 6585 (as set up by new_form() or set_form_fields()</p> 6586 6587 <p>It is also possible to traverse the fields as if they 6588 had been sorted in screen-position order, so the sequence 6589 goes left-to-right and top-to-bottom. To do this, use the 6590 second group of four sorted-movement requests.</p> 6591 6592 <p>Finally, it is possible to move between fields using 6593 visual directions up, down, right, and left. To 6594 accomplish this, use the third group of four requests. 6595 Note, however, that the position of a form for purposes 6596 of these requests is its upper-left corner.</p> 6597 6598 <p>For example, suppose you have a multi-line field B, 6599 and two single-line fields A and C on the same line with 6600 B, with A to the left of B and C to the right of B. A 6601 REQ_MOVE_RIGHT from A will go to B only if A, B, and C 6602 all share the same first line; otherwise it will skip 6603 over B to C.</p> 6604 </div> 6605 6606 <div class="SECT3"> 6607 <hr> 6608 6609 <h4 class="SECT3"><a name="INTRAFIELDNAVREQ" id= 6610 "INTRAFIELDNAVREQ">18.6.3. Intra-Field Navigation 6611 Requests</a></h4> 6612 6613 <p>These requests drive movement of the edit cursor 6614 within the currently selected field.</p> 6615 6616 <ul> 6617 <li> 6618 <p><span class="emphasis"><i class= 6619 "EMPHASIS">REQ_NEXT_CHAR</i></span> Move to next 6620 character.</p> 6621 </li> 6622 6623 <li> 6624 <p><span class="emphasis"><i class= 6625 "EMPHASIS">REQ_PREV_CHAR</i></span> Move to previous 6626 character.</p> 6627 </li> 6628 6629 <li> 6630 <p><span class="emphasis"><i class= 6631 "EMPHASIS">REQ_NEXT_LINE</i></span> Move to next 6632 line.</p> 6633 </li> 6634 6635 <li> 6636 <p><span class="emphasis"><i class= 6637 "EMPHASIS">REQ_PREV_LINE</i></span> Move to previous 6638 line.</p> 6639 </li> 6640 6641 <li> 6642 <p><span class="emphasis"><i class= 6643 "EMPHASIS">REQ_NEXT_WORD</i></span> Move to next 6644 word.</p> 6645 </li> 6646 6647 <li> 6648 <p><span class="emphasis"><i class= 6649 "EMPHASIS">REQ_PREV_WORD</i></span> Move to previous 6650 word.</p> 6651 </li> 6652 6653 <li> 6654 <p><span class="emphasis"><i class= 6655 "EMPHASIS">REQ_BEG_FIELD</i></span> Move to beginning 6656 of field.</p> 6657 </li> 6658 6659 <li> 6660 <p><span class="emphasis"><i class= 6661 "EMPHASIS">REQ_END_FIELD</i></span> Move to end of 6662 field.</p> 6663 </li> 6664 6665 <li> 6666 <p><span class="emphasis"><i class= 6667 "EMPHASIS">REQ_BEG_LINE</i></span> Move to beginning 6668 of line.</p> 6669 </li> 6670 6671 <li> 6672 <p><span class="emphasis"><i class= 6673 "EMPHASIS">REQ_END_LINE</i></span> Move to end of 6674 line.</p> 6675 </li> 6676 6677 <li> 6678 <p><span class="emphasis"><i class= 6679 "EMPHASIS">REQ_LEFT_CHAR</i></span> Move left in 6680 field.</p> 6681 </li> 6682 6683 <li> 6684 <p><span class="emphasis"><i class= 6685 "EMPHASIS">REQ_RIGHT_CHAR</i></span> Move right in 6686 field.</p> 6687 </li> 6688 6689 <li> 6690 <p><span class="emphasis"><i class= 6691 "EMPHASIS">REQ_UP_CHAR</i></span> Move up in 6692 field.</p> 6693 </li> 6694 6695 <li> 6696 <p><span class="emphasis"><i class= 6697 "EMPHASIS">REQ_DOWN_CHAR</i></span> Move down in 6698 field.</p> 6699 </li> 6700 </ul> 6701 6702 <p>Each word is separated from the previous and next 6703 characters by whitespace. The commands to move to 6704 beginning and end of line or field look for the first or 6705 last non-pad character in their ranges.</p> 6706 </div> 6707 6708 <div class="SECT3"> 6709 <hr> 6710 6711 <h4 class="SECT3"><a name="SCROLLREQ" id= 6712 "SCROLLREQ">18.6.4. Scrolling Requests</a></h4> 6713 6714 <p>Fields that are dynamic and have grown and fields 6715 explicitly created with offscreen rows are scrollable. 6716 One-line fields scroll horizontally; multi-line fields 6717 scroll vertically. Most scrolling is triggered by editing 6718 and intra-field movement (the library scrolls the field 6719 to keep the cursor visible). It is possible to explicitly 6720 request scrolling with the following requests:</p> 6721 6722 <ul> 6723 <li> 6724 <p><span class="emphasis"><i class= 6725 "EMPHASIS">REQ_SCR_FLINE</i></span> Scroll vertically 6726 forward a line.</p> 6727 </li> 6728 6729 <li> 6730 <p><span class="emphasis"><i class= 6731 "EMPHASIS">REQ_SCR_BLINE</i></span> Scroll vertically 6732 backward a line.</p> 6733 </li> 6734 6735 <li> 6736 <p><span class="emphasis"><i class= 6737 "EMPHASIS">REQ_SCR_FPAGE</i></span> Scroll vertically 6738 forward a page.</p> 6739 </li> 6740 6741 <li> 6742 <p><span class="emphasis"><i class= 6743 "EMPHASIS">REQ_SCR_BPAGE</i></span> Scroll vertically 6744 backward a page.</p> 6745 </li> 6746 6747 <li> 6748 <p><span class="emphasis"><i class= 6749 "EMPHASIS">REQ_SCR_FHPAGE</i></span> Scroll 6750 vertically forward half a page.</p> 6751 </li> 6752 6753 <li> 6754 <p><span class="emphasis"><i class= 6755 "EMPHASIS">REQ_SCR_BHPAGE</i></span> Scroll 6756 vertically backward half a page.</p> 6757 </li> 6758 6759 <li> 6760 <p><span class="emphasis"><i class= 6761 "EMPHASIS">REQ_SCR_FCHAR</i></span> Scroll 6762 horizontally forward a character.</p> 6763 </li> 6764 6765 <li> 6766 <p><span class="emphasis"><i class= 6767 "EMPHASIS">REQ_SCR_BCHAR</i></span> Scroll 6768 horizontally backward a character.</p> 6769 </li> 6770 6771 <li> 6772 <p><span class="emphasis"><i class= 6773 "EMPHASIS">REQ_SCR_HFLINE</i></span> Scroll 6774 horizontally one field width forward.</p> 6775 </li> 6776 6777 <li> 6778 <p><span class="emphasis"><i class= 6779 "EMPHASIS">REQ_SCR_HBLINE</i></span> Scroll 6780 horizontally one field width backward.</p> 6781 </li> 6782 6783 <li> 6784 <p><span class="emphasis"><i class= 6785 "EMPHASIS">REQ_SCR_HFHALF</i></span> Scroll 6786 horizontally one half field width forward.</p> 6787 </li> 6788 6789 <li> 6790 <p><span class="emphasis"><i class= 6791 "EMPHASIS">REQ_SCR_HBHALF</i></span> Scroll 6792 horizontally one half field width backward.</p> 6793 </li> 6794 </ul> 6795 6796 <p>For scrolling purposes, a page of a field is the 6797 height of its visible part.</p> 6798 </div> 6799 6800 <div class="SECT3"> 6801 <hr> 6802 6803 <h4 class="SECT3"><a name="EDITREQ" id="EDITREQ">18.6.5. 6804 Editing Requests</a></h4> 6805 6806 <p>When you pass the forms driver an ASCII character, it 6807 is treated as a request to add the character to the 6808 field's data buffer. Whether this is an insertion or a 6809 replacement depends on the field's edit mode (insertion 6810 is the default.</p> 6811 6812 <p>The following requests support editing the field and 6813 changing the edit mode:</p> 6814 6815 <ul> 6816 <li> 6817 <p><span class="emphasis"><i class= 6818 "EMPHASIS">REQ_INS_MODE</i></span> Set insertion 6819 mode.</p> 6820 </li> 6821 6822 <li> 6823 <p><span class="emphasis"><i class= 6824 "EMPHASIS">REQ_OVL_MODE</i></span> Set overlay 6825 mode.</p> 6826 </li> 6827 6828 <li> 6829 <p><span class="emphasis"><i class= 6830 "EMPHASIS">REQ_NEW_LINE</i></span> New line request 6831 (see below for explanation).</p> 6832 </li> 6833 6834 <li> 6835 <p><span class="emphasis"><i class= 6836 "EMPHASIS">REQ_INS_CHAR</i></span> Insert space at 6837 character location.</p> 6838 </li> 6839 6840 <li> 6841 <p><span class="emphasis"><i class= 6842 "EMPHASIS">REQ_INS_LINE</i></span> Insert blank line 6843 at character location.</p> 6844 </li> 6845 6846 <li> 6847 <p><span class="emphasis"><i class= 6848 "EMPHASIS">REQ_DEL_CHAR</i></span> Delete character 6849 at cursor.</p> 6850 </li> 6851 6852 <li> 6853 <p><span class="emphasis"><i class= 6854 "EMPHASIS">REQ_DEL_PREV</i></span> Delete previous 6855 word at cursor.</p> 6856 </li> 6857 6858 <li> 6859 <p><span class="emphasis"><i class= 6860 "EMPHASIS">REQ_DEL_LINE</i></span> Delete line at 6861 cursor.</p> 6862 </li> 6863 6864 <li> 6865 <p><span class="emphasis"><i class= 6866 "EMPHASIS">REQ_DEL_WORD</i></span> Delete word at 6867 cursor.</p> 6868 </li> 6869 6870 <li> 6871 <p><span class="emphasis"><i class= 6872 "EMPHASIS">REQ_CLR_EOL</i></span> Clear to end of 6873 line.</p> 6874 </li> 6875 6876 <li> 6877 <p><span class="emphasis"><i class= 6878 "EMPHASIS">REQ_CLR_EOF</i></span> Clear to end of 6879 field.</p> 6880 </li> 6881 6882 <li> 6883 <p><span class="emphasis"><i class= 6884 "EMPHASIS">REQ_CLR_FIELD</i></span> Clear entire 6885 field.</p> 6886 </li> 6887 </ul> 6888 6889 <p>The behavior of the REQ_NEW_LINE and REQ_DEL_PREV 6890 requests is complicated and partly controlled by a pair 6891 of forms options. The special cases are triggered when 6892 the cursor is at the beginning of a field, or on the last 6893 line of the field.</p> 6894 6895 <p>First, we consider REQ_NEW_LINE:</p> 6896 6897 <p>The normal behavior of REQ_NEW_LINE in insert mode is 6898 to break the current line at the position of the edit 6899 cursor, inserting the portion of the current line after 6900 the cursor as a new line following the current and moving 6901 the cursor to the beginning of that new line (you may 6902 think of this as inserting a newline in the field 6903 buffer).</p> 6904 6905 <p>The normal behavior of REQ_NEW_LINE in overlay mode is 6906 to clear the current line from the position of the edit 6907 cursor to end of line. The cursor is then moved to the 6908 beginning of the next line.</p> 6909 6910 <p>However, REQ_NEW_LINE at the beginning of a field, or 6911 on the last line of a field, instead does a 6912 REQ_NEXT_FIELD. O_NL_OVERLOAD option is off, this special 6913 action is disabled.</p> 6914 6915 <p>Now, let us consider REQ_DEL_PREV:</p> 6916 6917 <p>The normal behavior of REQ_DEL_PREV is to delete the 6918 previous character. If insert mode is on, and the cursor 6919 is at the start of a line, and the text on that line will 6920 fit on the previous one, it instead appends the contents 6921 of the current line to the previous one and deletes the 6922 current line (you may think of this as deleting a newline 6923 from the field buffer).</p> 6924 6925 <p>However, REQ_DEL_PREV at the beginning of a field is 6926 instead treated as a REQ_PREV_FIELD.</p> 6927 6928 <p>If the O_BS_OVERLOAD option is off, this special 6929 action is disabled and the forms driver just returns 6930 E_REQUEST_DENIED.</p> 6931 </div> 6932 6933 <div class="SECT3"> 6934 <hr> 6935 6936 <h4 class="SECT3"><a name="ORDERREQ" id= 6937 "ORDERREQ">18.6.6. Order Requests</a></h4> 6938 6939 <p>If the type of your field is ordered, and has 6940 associated functions for getting the next and previous 6941 values of the type from a given value, there are requests 6942 that can fetch that value into the field buffer:</p> 6943 6944 <ul> 6945 <li> 6946 <p><span class="emphasis"><i class= 6947 "EMPHASIS">REQ_NEXT_CHOICE</i></span> Place the 6948 successor value of the current value in the 6949 buffer.</p> 6950 </li> 6951 6952 <li> 6953 <p><span class="emphasis"><i class= 6954 "EMPHASIS">REQ_PREV_CHOICE</i></span> Place the 6955 predecessor value of the current value in the 6956 buffer.</p> 6957 </li> 6958 </ul> 6959 6960 <p>Of the built-in field types, only TYPE_ENUM has 6961 built-in successor and predecessor functions. When you 6962 define a field type of your own (see Custom Validation 6963 Types), you can associate our own ordering functions.</p> 6964 </div> 6965 6966 <div class="SECT3"> 6967 <hr> 6968 6969 <h4 class="SECT3"><a name="APPLICCOMMANDS" id= 6970 "APPLICCOMMANDS">18.6.7. Application Commands</a></h4> 6971 6972 <p>Form requests are represented as integers above the 6973 curses value greater than KEY_MAX and less than or equal 6974 to the constant MAX_COMMAND. A value within this range 6975 gets ignored by form_driver(). So this can be used for 6976 any purpose by the application. It can be treated as an 6977 application specific action and take corresponding 6978 action.</p> 6979 </div> 6980 </div> 6981 </div> 6982 6983 <div class="SECT1"> 6984 <hr> 6985 6986 <h2 class="SECT1"><a name="TOOLS" id="TOOLS">19. Tools and 6987 Widget Libraries</a></h2> 6988 6989 <p>Now that you have seen the capabilities of ncurses and its 6990 sister libraries, you are rolling your sleeves up and gearing 6991 for a project that heavily manipulates screen. But wait.. It 6992 can be pretty difficult to write and maintain complex GUI 6993 widgets in plain ncurses or even with the additional 6994 libraries. There are some ready-to-use tools and widget 6995 libraries that can be used instead of writing your own 6996 widgets. You can use some of them, get ideas from the code, 6997 or even extend them.</p> 6998 6999 <div class="SECT2"> 7000 <hr> 7001 7002 <h3 class="SECT2"><a name="CDK" id="CDK">19.1. CDK (Curses 7003 Development Kit)</a></h3> 7004 7005 <p>In the author's words</p> 7006 7007 <p><span class="emphasis"><i class="EMPHASIS">CDK stands 7008 for 'Curses Development Kit' and it currently contains 21 7009 ready to use widgets which facilitate the speedy 7010 development of full screen curses programs.</i></span> 7011 </p> 7012 7013 <p>The kit provides some useful widgets, which can be used 7014 in your programs directly. It is pretty well written and 7015 the documentation is very good. The examples in the 7016 examples directory can be a good place to start for 7017 beginners. The CDK can be downloaded from <a href= 7018 "https://invisible-island.net/cdk/" target= 7019 "_top">https://invisible-island.net/cdk/</a> . Follow the 7020 instructions in README file to install it.</p> 7021 7022 <div class="SECT3"> 7023 <hr> 7024 7025 <h4 class="SECT3"><a name="WIDGETLIST" id= 7026 "WIDGETLIST">19.1.1. Widget List</a></h4> 7027 7028 <p>The following is the list of widgets provided with cdk 7029 and their description.</p> 7030 7031 <pre class= 7032 "PROGRAMLISTING">Widget Type Quick Description 7033=========================================================================== 7034Alphalist Allows a user to select from a list of words, with 7035 the ability to narrow the search list by typing in a 7036 few characters of the desired word. 7037Buttonbox This creates a multiple button widget. 7038Calendar Creates a little simple calendar widget. 7039Dialog Prompts the user with a message, and the user 7040 can pick an answer from the buttons provided. 7041Entry Allows the user to enter various types of information. 7042File Selector A file selector built from Cdk base widgets. This 7043 example shows how to create more complicated widgets 7044 using the Cdk widget library. 7045Graph Draws a graph. 7046Histogram Draws a histogram. 7047Item List Creates a pop up field which allows the user to select 7048 one of several choices in a small field. Very useful 7049 for things like days of the week or month names. 7050Label Displays messages in a pop up box, or the label can be 7051 considered part of the screen. 7052Marquee Displays a message in a scrolling marquee. 7053Matrix Creates a complex matrix with lots of options. 7054Menu Creates a pull-down menu interface. 7055Multiple Line Entry A multiple line entry field. Very useful 7056 for long fields. (like a description 7057 field) 7058Radio List Creates a radio button list. 7059Scale Creates a numeric scale. Used for allowing a user to 7060 pick a numeric value and restrict them to a range of 7061 values. 7062Scrolling List Creates a scrolling list/menu list. 7063Scrolling Window Creates a scrolling log file viewer. Can add 7064 information into the window while its running. 7065 A good widget for displaying the progress of 7066 something. (akin to a console window) 7067Selection List Creates a multiple option selection list. 7068Slider Akin to the scale widget, this widget provides a 7069 visual slide bar to represent the numeric value. 7070Template Creates a entry field with character sensitive 7071 positions. Used for pre-formatted fields like 7072 dates and phone numbers. 7073Viewer This is a file/information viewer. Very useful 7074 when you need to display loads of information. 7075===========================================================================</pre> 7076 <p>A few of the widgets are modified by Thomas Dickey in 7077 recent versions.</p> 7078 </div> 7079 7080 <div class="SECT3"> 7081 <hr> 7082 7083 <h4 class="SECT3"><a name="CDKATTRACT" id= 7084 "CDKATTRACT">19.1.2. Some Attractive Features</a></h4> 7085 7086 <p>Apart from making our life easier with readily usable 7087 widgets, cdk solves one frustrating problem with printing 7088 multi colored strings, justified strings elegantly. 7089 Special formatting tags can be embedded in the strings 7090 which are passed to CDK functions. For Example</p> 7091 7092 <p>If the string</p> 7093 7094 <pre class= 7095 "PROGRAMLISTING">"</B/1>This line should have a yellow foreground and a blue 7096background.<!1>"</pre> 7097 <p>given as a parameter to newCDKLabel(), it prints the 7098 line with yellow foreground and blue background. There 7099 are other tags available for justifying string, embedding 7100 special drawing characters, etc. Please refer to the man 7101 page cdk_display(3X) for details. The man page explains 7102 the usage with nice examples.</p> 7103 </div> 7104 7105 <div class="SECT3"> 7106 <hr> 7107 7108 <h4 class="SECT3"><a name="CDKCONCLUSION" id= 7109 "CDKCONCLUSION">19.1.3. Conclusion</a></h4> 7110 7111 <p>All in all, CDK is a well-written package of widgets, 7112 which if used properly can form a strong frame work for 7113 developing complex GUI.</p> 7114 </div> 7115 </div> 7116 7117 <div class="SECT2"> 7118 <hr> 7119 7120 <h3 class="SECT2"><a name="DIALOG" id="DIALOG">19.2. The 7121 dialog</a></h3> 7122 7123 <p>Long long ago, in September 1994, when few people knew 7124 linux, Jeff Tranter wrote an <a href= 7125 "http://www2.linuxjournal.com/lj-issues/issue5/2807.html" 7126 target="_top">article</a> on dialog in Linux Journal. He 7127 starts the article with these words..</p> 7128 7129 <p><span class="emphasis"><i class="EMPHASIS">Linux is 7130 based on the Unix operating system, but also features a 7131 number of unique and useful kernel features and application 7132 programs that often go beyond what is available under Unix. 7133 One little-known gem is "dialog", a utility for creating 7134 professional-looking dialog boxes from within shell 7135 scripts. This article presents a tutorial introduction to 7136 the dialog utility, and shows examples of how and where it 7137 can be used</i></span> 7138 </p> 7139 7140 <p>As he explains, dialog is a real gem in making 7141 professional-looking dialog boxes with ease. It creates a 7142 variety of dialog boxes, menus, check lists, etc. It is 7143 usually installed by default. If not, you can download it 7144 from <a href="https://invisible-island.net/dialog/" target= 7145 "_top">Thomas Dickey</a>'s site.</p> 7146 7147 <p>The above-mentioned article gives a very good overview 7148 of its uses and capabilities. The man page has more 7149 details. It can be used in variety of situations. One good 7150 example is building of linux kernel in text mode. Linux 7151 kernel uses a modified version of dialog tailored for its 7152 needs.</p> 7153 7154 <p>dialog was initially designed to be used with shell 7155 scripts. If you want to use its functionality in a c 7156 program, then you can use libdialog. The documentation 7157 regarding this is sparse. Definitive reference is the 7158 dialog.h header file which comes with the library. You may 7159 need to hack here and there to get the required output. The 7160 source is easily customizable. I have used it on a number 7161 of occasions by modifying the code.</p> 7162 </div> 7163 7164 <div class="SECT2"> 7165 <hr> 7166 7167 <h3 class="SECT2"><a name="PERLCURSES" id= 7168 "PERLCURSES">19.3. Perl Curses Modules CURSES::FORM and 7169 CURSES::WIDGETS</a></h3> 7170 7171 <p>The perl module Curses, Curses::Form and Curses::Widgets 7172 give access to curses from perl. If you have curses and 7173 basic perl is installed, you can get these modules from 7174 <a href="http://www.cpan.org/modules/01modules.index.html" 7175 target="_top">CPAN All Modules page</a>. Get the three 7176 zipped modules in the Curses category. Once installed you 7177 can use these modules from perl scripts like any other 7178 module. For more information on perl modules see perlmod 7179 man page. The above modules come with good documentation 7180 and they have some demo scripts to test the functionality. 7181 Though the widgets provided are very rudimentary, these 7182 modules provide good access to curses library from 7183 perl.</p> 7184 7185 <p>Some of my code examples are converted to perl by 7186 Anuradha Ratnaweera and they are available in the 7187 <tt class="LITERAL">perl</tt> directory.</p> 7188 7189 <p>For more information see man pages Curses(3) , 7190 Curses::Form(3) and Curses::Widgets(3). These pages are 7191 installed only when the above modules are acquired and 7192 installed.</p> 7193 </div> 7194 </div> 7195 7196 <div class="SECT1"> 7197 <hr> 7198 7199 <h2 class="SECT1"><a name="JUSTFORFUN" id="JUSTFORFUN">20. 7200 Just For Fun !!!</a></h2> 7201 7202 <p>This section contains few programs written by me just for 7203 fun. They don't signify a better programming practice or the 7204 best way of using ncurses. They are provided here so as to 7205 allow beginners to get ideas and add more programs to this 7206 section. If you have written a couple of nice, simple 7207 programs in curses and want them to included here, contact 7208 <a href="mailto:ppadala@gmail.com" target="_top">me</a>.</p> 7209 7210 <div class="SECT2"> 7211 <hr> 7212 7213 <h3 class="SECT2"><a name="GAMEOFLIFE" id= 7214 "GAMEOFLIFE">20.1. The Game of Life</a></h3> 7215 7216 <p>Game of life is a wonder of math. In <a href= 7217 "http://www.math.com/students/wonders/life/life.html" 7218 target="_top">Paul Callahan</a>'s words</p> 7219 7220 <pre class="PROGRAMLISTING"><span class="emphasis"><i class= 7221 "EMPHASIS">The Game of Life (or simply Life) is not a game in the conventional sense. There 7222are no players, and no winning or losing. Once the "pieces" are placed in the 7223starting position, the rules determine everything that happens later. 7224Nevertheless, Life is full of surprises! In most cases, it is impossible to look 7225at a starting position (or pattern) and see what will happen in the future. The 7226only way to find out is to follow the rules of the game.</i></span></pre> 7227 <p>This program starts with a simple inverted U pattern and 7228 shows how wonderful life works. There is a lot of room for 7229 improvement in the program. You can let the user enter 7230 pattern of his choice or even take input from a file. You 7231 can also change rules and play with a lot of variations. 7232 Search on <a href="https://www.google.com" target= 7233 "_top">google</a> for interesting information on game of 7234 life.</p> 7235 7236 <p><span class="emphasis"><i class="EMPHASIS">File Path: 7237 JustForFun/life.c</i></span> 7238 </p> 7239 </div> 7240 7241 <div class="SECT2"> 7242 <hr> 7243 7244 <h3 class="SECT2"><a name="MAGIC" id="MAGIC">20.2. Magic 7245 Square</a></h3> 7246 7247 <p>Magic Square, another wonder of math, is very simple to 7248 understand but very difficult to make. In a magic square 7249 sum of the numbers in each row, each column is equal. Even 7250 diagonal sum can be equal. There are many variations which 7251 have special properties.</p> 7252 7253 <p>This program creates a simple magic square of odd 7254 order.</p> 7255 7256 <p><span class="emphasis"><i class="EMPHASIS">File Path: 7257 JustForFun/magic.c</i></span> 7258 </p> 7259 </div> 7260 7261 <div class="SECT2"> 7262 <hr> 7263 7264 <h3 class="SECT2"><a name="HANOI" id="HANOI">20.3. Towers 7265 of Hanoi</a></h3> 7266 7267 <p>The famous towers of hanoi solver. The aim of the game 7268 is to move the disks on the first peg to last peg, using 7269 middle peg as a temporary stay. The catch is not to place a 7270 larger disk over a small disk at any time.</p> 7271 7272 <p><span class="emphasis"><i class="EMPHASIS">File Path: 7273 JustForFun/hanoi.c</i></span> 7274 </p> 7275 </div> 7276 7277 <div class="SECT2"> 7278 <hr> 7279 7280 <h3 class="SECT2"><a name="QUEENS" id="QUEENS">20.4. Queens 7281 Puzzle</a></h3> 7282 7283 <p>The objective of the famous N-Queen puzzle is to put N 7284 queens on a N X N chess board without attacking each 7285 other.</p> 7286 7287 <p>This program solves it with a simple backtracking 7288 technique.</p> 7289 7290 <p><span class="emphasis"><i class="EMPHASIS">File Path: 7291 JustForFun/queens.c</i></span> 7292 </p> 7293 </div> 7294 7295 <div class="SECT2"> 7296 <hr> 7297 7298 <h3 class="SECT2"><a name="SHUFFLE" id="SHUFFLE">20.5. 7299 Shuffle</a></h3> 7300 7301 <p>A fun game, if you have time to kill.</p> 7302 7303 <p><span class="emphasis"><i class="EMPHASIS">File Path: 7304 JustForFun/shuffle.c</i></span> 7305 </p> 7306 </div> 7307 7308 <div class="SECT2"> 7309 <hr> 7310 7311 <h3 class="SECT2"><a name="TT" id="TT">20.6. Typing 7312 Tutor</a></h3> 7313 7314 <p>A simple typing tutor, I created more out of need than 7315 for ease of use. If you know how to put your fingers 7316 correctly on the keyboard, but lack practice, this can be 7317 helpful.</p> 7318 7319 <p><span class="emphasis"><i class="EMPHASIS">File Path: 7320 JustForFun/tt.c</i></span> 7321 </p> 7322 </div> 7323 </div> 7324 7325 <div class="SECT1"> 7326 <hr> 7327 7328 <h2 class="SECT1"><a name="REF" id="REF">21. References</a></h2> 7329 7330 <ul> 7331 <li> 7332 <p>NCURSES man pages</p> 7333 </li> 7334 7335 <li> 7336 <p>NCURSES FAQ at <a href= 7337 "https://invisible-island.net/ncurses/ncurses.faq.html" 7338 target= 7339 "_top">https://invisible-island.net/ncurses/ncurses.faq.html</a></p> 7340 </li> 7341 7342 <li> 7343 <p>Writing programs with NCURSES by Eric Raymond and Zeyd 7344 M. Ben-Halim at <a href= 7345 "https://invisible-island.net/ncurses/ncurses-intro.html" 7346 target= 7347 "_top">https://invisible-island.net/ncurses/ncurses-intro.html</a> 7348 - somewhat obsolete. I was inspired by this document and 7349 the structure of this HOWTO follows from the original 7350 document</p> 7351 </li> 7352 </ul> 7353 </div> 7354 </div> 7355</body> 7356</html> 7357