blob: 9a3f078d2f1c697f9c68cb37fa12d1d766775d15 [file] [log] [blame]
micky3879b9f5e72025-07-08 18:04:53 -04001<!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">&lt;<a href=
24 "mailto:ppadala@gmail.com">ppadala@gmail.com</a>&gt;</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&lt;version&gt;.tar.gz # unzip and untar the archive
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530783 cd ncurses&lt;version&gt; # cd to the directory
784 ./configure # configure the build according to your
785 # environment
786 make # make it
787 su root # become root
micky3879b9f5e72025-07-08 18:04:53 -0400788 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 &lt;downloaded rpm&gt;</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
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530829 |
830 |----&gt; JustForFun -- just for fun programs
831 |----&gt; basics -- basic programs
832 |----&gt; demo -- output files go into this directory after make
833 | |
834 | |----&gt; exe -- exe files of all example programs
835 |----&gt; forms -- programs related to form library
836 |----&gt; menus -- programs related to menus library
837 |----&gt; panels -- programs related to panels library
838 |----&gt; perl -- perl equivalents of the examples (contributed
839 | by Anuradha Ratnaweera)
840 |----&gt; Makefile -- the top level Makefile
841 |----&gt; README -- the top level README file. contains instructions
micky3879b9f5e72025-07-08 18:04:53 -0400842 |----&gt; 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
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530848--------------------------------------
849JustForFun
850 |
851 |----&gt; hanoi.c -- The Towers of Hanoi Solver
852 |----&gt; life.c -- The Game of Life demo
853 |----&gt; magic.c -- An Odd Order Magic Square builder
854 |----&gt; queens.c -- The famous N-Queens Solver
855 |----&gt; shuffle.c -- A fun game, if you have time to kill
856 |----&gt; tt.c -- A very trivial typing tutor
857
858 basics
859 |
860 |----&gt; acs_vars.c -- ACS_ variables example
861 |----&gt; hello_world.c -- Simple "Hello World" Program
862 |----&gt; init_func_example.c -- Initialization functions example
863 |----&gt; key_code.c -- Shows the scan code of the key pressed
864 |----&gt; mouse_menu.c -- A menu accessible by mouse
865 |----&gt; other_border.c -- Shows usage of other border functions apa
866 | -- rt from box()
867 |----&gt; printw_example.c -- A very simple printw() example
868 |----&gt; scanw_example.c -- A very simple getstr() example
869 |----&gt; simple_attr.c -- A program that can print a c file with
870 | -- comments in attribute
871 |----&gt; simple_color.c -- A simple example demonstrating colors
872 |----&gt; simple_key.c -- A menu accessible with keyboard UP, DOWN
873 | -- arrows
874 |----&gt; temp_leave.c -- Demonstrates temporarily leaving curses mode
875 |----&gt; win_border.c -- Shows Creation of windows and borders
876 |----&gt; with_chgat.c -- chgat() usage example
877
878 forms
879 |
880 |----&gt; form_attrib.c -- Usage of field attributes
881 |----&gt; form_options.c -- Usage of field options
882 |----&gt; form_simple.c -- A simple form example
883 |----&gt; form_win.c -- Demo of windows associated with forms
884
885 menus
886 |
887 |----&gt; menu_attrib.c -- Usage of menu attributes
micky3879b9f5e72025-07-08 18:04:53 -0400888 |----&gt; menu_item_data.c -- Usage of item_name(), etc. functions
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530889 |----&gt; menu_multi_column.c -- Creates multi columnar menus
890 |----&gt; menu_scroll.c -- Demonstrates scrolling capability of menus
891 |----&gt; menu_simple.c -- A simple menu accessed by arrow keys
892 |----&gt; menu_toggle.c -- Creates multi valued menus and explains
893 | -- REQ_TOGGLE_ITEM
894 |----&gt; menu_userptr.c -- Usage of user pointer
895 |----&gt; menu_win.c -- Demo of windows associated with menus
896
897 panels
898 |
899 |----&gt; panel_browse.c -- Panel browsing through tab. Usage of user
900 | -- pointer
901 |----&gt; panel_hide.c -- Hiding and Un hiding of panels
902 |----&gt; panel_resize.c -- Moving and resizing of panels
903 |----&gt; panel_simple.c -- A simple panel example
904
905 perl
micky3879b9f5e72025-07-08 18:04:53 -0400906 |----&gt; 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">&#13; Get both the source and the tar,gzipped programs, available at
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530985 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 &lt;path to docbook html stylesheet&gt;
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 &lt;path to docbook html stylesheet&gt; -V nochunks
999 NCURSES-Programming-HOWTO.sgml &gt; NCURSES-ONE-BIG-FILE.html
1000 then use htmldoc to get pdf file with
1001 htmldoc --size universal -t pdf --firstpage p1 -f &lt;output file name.pdf&gt;
1002 NCURSES-ONE-BIG-FILE.html
1003 for ps, you would use
1004 htmldoc --size universal -t ps --firstpage p1 -f &lt;output file name.ps&gt;
micky3879b9f5e72025-07-08 18:04:53 -04001005 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 &copy; 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 &lt;ncurses.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301140 .
1141 .
1142 .
1143
micky3879b9f5e72025-07-08 18:04:53 -04001144 compile and link: gcc &lt;program file&gt; -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 &lt;curses.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301152
1153int main()
micky3879b9f5e72025-07-08 18:04:53 -04001154{
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 */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301160
micky3879b9f5e72025-07-08 18:04:53 -04001161 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 &lt;curses.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301390
1391int main()
micky3879b9f5e72025-07-08 18:04:53 -04001392{ int ch;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301393
micky3879b9f5e72025-07-08 18:04:53 -04001394 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 */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301398
micky3879b9f5e72025-07-08 18:04:53 -04001399 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 */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301417
micky3879b9f5e72025-07-08 18:04:53 -04001418 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 &lt;enter&gt; 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 */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301478 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 */
micky3879b9f5e72025-07-08 18:04:53 -04001482 /* 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 &lt;curses.h&gt;
1672#include &lt;string.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301673
1674int main()
1675{
micky3879b9f5e72025-07-08 18:04:53 -04001676 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 */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301681 mvprintw(row/2,(col-strlen(mesg))/2,"%s",mesg);
micky3879b9f5e72025-07-08 18:04:53 -04001682 /* print the message at the center of the screen */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301683 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;
micky3879b9f5e72025-07-08 18:04:53 -04001690}</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 &lt;curses.h&gt;
1868#include &lt;string.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301869
1870int main()
1871{
micky3879b9f5e72025-07-08 18:04:53 -04001872 char mesg[]="Enter a string: "; /* message to be appeared on the screen */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301873 char str[80];
micky3879b9f5e72025-07-08 18:04:53 -04001874 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 */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301878 mvprintw(row/2,(col-strlen(mesg))/2,"%s",mesg);
micky3879b9f5e72025-07-08 18:04:53 -04001879 /* print the message at the center of the screen */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301880 getstr(str);
1881 mvprintw(LINES - 2, 0, "You Entered: %s", str);
1882 getch();
1883 endwin();
1884
1885 return 0;
micky3879b9f5e72025-07-08 18:04:53 -04001886}</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" &lt;spainhou@bellsouth.net&gt; */
1911#include &lt;curses.h&gt;
1912#include &lt;stdlib.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301913
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 {
micky3879b9f5e72025-07-08 18:04:53 -04001923 printf("Usage: %s &lt;a c file name&gt;\n", argv[0]);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301924 exit(1);
1925 }
1926 fp = fopen(argv[1], "r");
1927 if(fp == NULL)
1928 {
1929 perror("Cannot open input file");
1930 exit(1);
1931 }
micky3879b9f5e72025-07-08 18:04:53 -04001932 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 */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301935 {
micky3879b9f5e72025-07-08 18:04:53 -04001936 getyx(stdscr, y, x); /* get the current cursor position */
1937 if(y == (row - 1)) /* are we are at the end of the screen */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301938 {
micky3879b9f5e72025-07-08 18:04:53 -04001939 printw("&lt;-Press Any Key-&gt;"); /* tell the user to press a key */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301940 getch();
micky3879b9f5e72025-07-08 18:04:53 -04001941 clear(); /* clear the screen */
1942 move(0, 0); /* start at the beginning of the screen */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301943 }
micky3879b9f5e72025-07-08 18:04:53 -04001944 if(prev == '/' &amp;&amp; ch == '*') /* If it is / and * then only
1945 * switch bold on */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301946 {
micky3879b9f5e72025-07-08 18:04:53 -04001947 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 */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301951 }
1952 else
1953 printw("%c", ch);
1954 refresh();
micky3879b9f5e72025-07-08 18:04:53 -04001955 if(prev == '*' &amp;&amp; ch == '/')
1956 attroff(A_BOLD); /* Switch it off once we got *
1957 * and then / */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301958 prev = ch;
1959 }
micky3879b9f5e72025-07-08 18:04:53 -04001960 endwin(); /* End curses mode */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301961 fclose(fp);
1962 return 0;
micky3879b9f5e72025-07-08 18:04:53 -04001963}</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 &lt;curses.h&gt; can be passed to these functions.</p>
2004
2005 <pre class="PROGRAMLISTING">
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302006 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
micky3879b9f5e72025-07-08 18:04:53 -04002018 </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 &lt;curses.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302131
2132int main(int argc, char *argv[])
micky3879b9f5e72025-07-08 18:04:53 -04002133{ 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>
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302155
micky3879b9f5e72025-07-08 18:04:53 -04002156 <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 &lt;curses.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302221
2222WINDOW *create_newwin(int height, int width, int starty, int startx);
2223void destroy_win(WINDOW *local_win);
2224
2225int main(int argc, char *argv[])
micky3879b9f5e72025-07-08 18:04:53 -04002226{ WINDOW *my_win;
2227 int startx, starty, width, height;
2228 int ch;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302229
micky3879b9f5e72025-07-08 18:04:53 -04002230 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 */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302234
micky3879b9f5e72025-07-08 18:04:53 -04002235 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);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302242
micky3879b9f5e72025-07-08 18:04:53 -04002243 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;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302266}
2267
2268WINDOW *create_newwin(int height, int width, int starty, int startx)
micky3879b9f5e72025-07-08 18:04:53 -04002269{ WINDOW *local_win;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302270
micky3879b9f5e72025-07-08 18:04:53 -04002271 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 */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302276
micky3879b9f5e72025-07-08 18:04:53 -04002277 return local_win;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302278}
2279
2280void destroy_win(WINDOW *local_win)
micky3879b9f5e72025-07-08 18:04:53 -04002281{
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"> +------------+
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302341 | |
2342 | |
2343 | |
2344 | |
2345 | |
2346 | |
micky3879b9f5e72025-07-08 18:04:53 -04002347 +------------+</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 &lt;curses.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302392
2393typedef struct _win_border_struct {
micky3879b9f5e72025-07-08 18:04:53 -04002394 chtype ls, rs, ts, bs,
2395 tl, tr, bl, br;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302396}WIN_BORDER;
2397
2398typedef struct _WIN_struct {
2399
micky3879b9f5e72025-07-08 18:04:53 -04002400 int startx, starty;
2401 int height, width;
2402 WIN_BORDER border;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302403}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[])
micky3879b9f5e72025-07-08 18:04:53 -04002410{ WIN win;
2411 int ch;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302412
micky3879b9f5e72025-07-08 18:04:53 -04002413 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);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302420
micky3879b9f5e72025-07-08 18:04:53 -04002421 /* Initialize the window parameters */
2422 init_win_params(&amp;win);
2423 print_win_params(&amp;win);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302424
micky3879b9f5e72025-07-08 18:04:53 -04002425 attron(COLOR_PAIR(1));
2426 printw("Press F1 to exit");
2427 refresh();
2428 attroff(COLOR_PAIR(1));
2429
2430 create_box(&amp;win, TRUE);
2431 while((ch = getch()) != KEY_F(1))
2432 { switch(ch)
2433 { case KEY_LEFT:
2434 create_box(&amp;win, FALSE);
2435 --win.startx;
2436 create_box(&amp;win, TRUE);
2437 break;
2438 case KEY_RIGHT:
2439 create_box(&amp;win, FALSE);
2440 ++win.startx;
2441 create_box(&amp;win, TRUE);
2442 break;
2443 case KEY_UP:
2444 create_box(&amp;win, FALSE);
2445 --win.starty;
2446 create_box(&amp;win, TRUE);
2447 break;
2448 case KEY_DOWN:
2449 create_box(&amp;win, FALSE);
2450 ++win.starty;
2451 create_box(&amp;win, TRUE);
2452 break;
2453 }
2454 }
2455 endwin(); /* End curses mode */
2456 return 0;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302457}
2458void init_win_params(WIN *p_win)
2459{
micky3879b9f5e72025-07-08 18:04:53 -04002460 p_win-&gt;height = 3;
2461 p_win-&gt;width = 10;
2462 p_win-&gt;starty = (LINES - p_win-&gt;height)/2;
2463 p_win-&gt;startx = (COLS - p_win-&gt;width)/2;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302464
micky3879b9f5e72025-07-08 18:04:53 -04002465 p_win-&gt;border.ls = '|';
2466 p_win-&gt;border.rs = '|';
2467 p_win-&gt;border.ts = '-';
2468 p_win-&gt;border.bs = '-';
2469 p_win-&gt;border.tl = '+';
2470 p_win-&gt;border.tr = '+';
2471 p_win-&gt;border.bl = '+';
2472 p_win-&gt;border.br = '+';
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302473
2474}
2475void print_win_params(WIN *p_win)
2476{
2477#ifdef _DEBUG
micky3879b9f5e72025-07-08 18:04:53 -04002478 mvprintw(25, 0, "%d %d %d %d", p_win-&gt;startx, p_win-&gt;starty,
2479 p_win-&gt;width, p_win-&gt;height);
2480 refresh();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302481#endif
2482}
2483void create_box(WIN *p_win, bool flag)
micky3879b9f5e72025-07-08 18:04:53 -04002484{ int i, j;
2485 int x, y, w, h;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302486
micky3879b9f5e72025-07-08 18:04:53 -04002487 x = p_win-&gt;startx;
2488 y = p_win-&gt;starty;
2489 w = p_win-&gt;width;
2490 h = p_win-&gt;height;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302491
micky3879b9f5e72025-07-08 18:04:53 -04002492 if(flag == TRUE)
2493 { mvaddch(y, x, p_win-&gt;border.tl);
2494 mvaddch(y, x + w, p_win-&gt;border.tr);
2495 mvaddch(y + h, x, p_win-&gt;border.bl);
2496 mvaddch(y + h, x + w, p_win-&gt;border.br);
2497 mvhline(y, x + 1, p_win-&gt;border.ts, w - 1);
2498 mvhline(y + h, x + 1, p_win-&gt;border.bs, w - 1);
2499 mvvline(y + 1, x, p_win-&gt;border.ls, h - 1);
2500 mvvline(y + 1, x + w, p_win-&gt;border.rs, h - 1);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302501
micky3879b9f5e72025-07-08 18:04:53 -04002502 }
2503 else
2504 for(j = y; j &lt;= y + h; ++j)
2505 for(i = x; i &lt;= x + w; ++i)
2506 mvaddch(j, i, ' ');
2507
2508 refresh();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302509
micky3879b9f5e72025-07-08 18:04:53 -04002510}</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 &lt;stdlib.h&gt;
2535#include &lt;string.h&gt;
2536#include &lt;curses.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302537
2538void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string);
2539int main(int argc, char *argv[])
micky3879b9f5e72025-07-08 18:04:53 -04002540{ 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);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302548
micky3879b9f5e72025-07-08 18:04:53 -04002549 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();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302554}
2555void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string)
micky3879b9f5e72025-07-08 18:04:53 -04002556{ int length, x, y;
2557 float temp;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302558
micky3879b9f5e72025-07-08 18:04:53 -04002559 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;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302568
micky3879b9f5e72025-07-08 18:04:53 -04002569 length = strlen(string);
2570 temp = (width - length)/ 2;
2571 x = startx + (int)temp;
2572 mvwprintw(win, y, x, "%s", string);
2573 refresh();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302574}
micky3879b9f5e72025-07-08 18:04:53 -04002575</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
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302611 COLOR_RED 1
2612 COLOR_GREEN 2
2613 COLOR_YELLOW 3
2614 COLOR_BLUE 4
2615 COLOR_MAGENTA 5
2616 COLOR_CYAN 6
micky3879b9f5e72025-07-08 18:04:53 -04002617 COLOR_WHITE 7</pre>
2618 </div>
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302619
micky3879b9f5e72025-07-08 18:04:53 -04002620 <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 &lt;curses.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302725
2726#define WIDTH 30
2727#define HEIGHT 10
2728
2729int startx = 0;
2730int starty = 0;
2731
2732char *choices[] = {
micky3879b9f5e72025-07-08 18:04:53 -04002733 "Choice 1",
2734 "Choice 2",
2735 "Choice 3",
2736 "Choice 4",
2737 "Exit",
2738 };
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302739int n_choices = sizeof(choices) / sizeof(char *);
2740void print_menu(WINDOW *menu_win, int highlight);
2741
2742int main()
micky3879b9f5e72025-07-08 18:04:53 -04002743{ WINDOW *menu_win;
2744 int highlight = 1;
2745 int choice = 0;
2746 int c;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302747
micky3879b9f5e72025-07-08 18:04:53 -04002748 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;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302792}
2793
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302794void print_menu(WINDOW *menu_win, int highlight)
2795{
micky3879b9f5e72025-07-08 18:04:53 -04002796 int x, y, i;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302797
micky3879b9f5e72025-07-08 18:04:53 -04002798 x = 2;
2799 y = 2;
2800 box(menu_win, 0, 0);
2801 for(i = 0; i &lt; 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);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302812}
micky3879b9f5e72025-07-08 18:04:53 -04002813</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
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302850 ---------------------------------------------------------------------
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
micky3879b9f5e72025-07-08 18:04:53 -04002875 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;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302892
2893 ch = getch();
2894 if(ch == KEY_MOUSE)
2895 if(getmouse(&amp;event) == OK)
2896 . /* Do some thing with the event */
2897 .
micky3879b9f5e72025-07-08 18:04:53 -04002898 .</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
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302903 {
2904 short id; /* ID to distinguish multiple devices */
2905 int x, y, z; /* event coordinates */
2906 mmask_t bstate; /* button state bits */
micky3879b9f5e72025-07-08 18:04:53 -04002907 } </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 &amp; 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 &lt;string.h&gt;
2937#include &lt;curses.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302938
2939#define WIDTH 30
micky3879b9f5e72025-07-08 18:04:53 -04002940#define HEIGHT 10
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302941
2942int startx = 0;
2943int starty = 0;
2944
micky3879b9f5e72025-07-08 18:04:53 -04002945char *choices[] = { "Choice 1",
2946 "Choice 2",
2947 "Choice 3",
2948 "Choice 4",
2949 "Exit",
2950 };
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302951
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()
micky3879b9f5e72025-07-08 18:04:53 -04002958{ int c, choice = 0;
2959 WINDOW *menu_win;
2960 MEVENT event;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302961
micky3879b9f5e72025-07-08 18:04:53 -04002962 /* Initialize curses */
2963 initscr();
2964 clear();
2965 noecho();
2966 cbreak(); //Line buffering disabled. pass on everything
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302967
micky3879b9f5e72025-07-08 18:04:53 -04002968 /* Try to put the window in the middle of screen */
2969 startx = (80 - WIDTH) / 2;
2970 starty = (24 - HEIGHT) / 2;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05302971
micky3879b9f5e72025-07-08 18:04:53 -04002972 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(&amp;event) == OK)
2989 { /* When the user clicks left mouse button */
2990 if(event.bstate &amp; BUTTON1_PRESSED)
2991 { report_choice(event.x + 1, event.y + 1, &amp;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 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303002end:
micky3879b9f5e72025-07-08 18:04:53 -04003003 endwin();
3004 return 0;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303005}
3006
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303007void print_menu(WINDOW *menu_win, int highlight)
3008{
micky3879b9f5e72025-07-08 18:04:53 -04003009 int x, y, i;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303010
micky3879b9f5e72025-07-08 18:04:53 -04003011 x = 2;
3012 y = 2;
3013 box(menu_win, 0, 0);
3014 for(i = 0; i &lt; 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);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303025}
3026
3027/* Report the choice according to mouse position */
3028void report_choice(int mouse_x, int mouse_y, int *p_choice)
micky3879b9f5e72025-07-08 18:04:53 -04003029{ int i,j, choice;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303030
micky3879b9f5e72025-07-08 18:04:53 -04003031 i = startx + 2;
3032 j = starty + 3;
3033
3034 for(choice = 0; choice &lt; n_choices; ++choice)
3035 if(mouse_y == j + choice &amp;&amp; mouse_x &gt;= i &amp;&amp; mouse_x &lt;= 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);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303088 /* win: window pointer
3089 * y, x: y, x co-ordinates will be put into this variables
micky3879b9f5e72025-07-08 18:04:53 -04003090 */</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
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303166 1 : normal or
micky3879b9f5e72025-07-08 18:04:53 -04003167 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 &lt;stdlib.h&gt;
3196#include &lt;curses.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303197
3198int main()
micky3879b9f5e72025-07-08 18:04:53 -04003199{
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 */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303213
micky3879b9f5e72025-07-08 18:04:53 -04003214 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 &lt;curses.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303241
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
micky3879b9f5e72025-07-08 18:04:53 -04003282 return 0;
3283}</span></pre>
3284 </div>
3285 </div>
3286 </div>
Steve Kondikae271bc2015-11-15 02:50:53 +01003287
micky3879b9f5e72025-07-08 18:04:53 -04003288 <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 &lt;panel.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303405 .
3406 .
3407 .
3408
micky3879b9f5e72025-07-08 18:04:53 -04003409 compile and link: gcc &lt;program file&gt; -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 &lt;panel.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303417
3418int main()
micky3879b9f5e72025-07-08 18:04:53 -04003419{ WINDOW *my_wins[3];
3420 PANEL *my_panels[3];
3421 int lines = 10, cols = 40, y = 2, x = 4, i;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303422
micky3879b9f5e72025-07-08 18:04:53 -04003423 initscr();
3424 cbreak();
3425 noecho();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303426
micky3879b9f5e72025-07-08 18:04:53 -04003427 /* 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);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303431
micky3879b9f5e72025-07-08 18:04:53 -04003432 /*
3433 * Create borders around the windows so that you can see the effect
3434 * of panels
3435 */
3436 for(i = 0; i &lt; 3; ++i)
3437 box(my_wins[i], 0, 0);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303438
micky3879b9f5e72025-07-08 18:04:53 -04003439 /* 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 */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303443
micky3879b9f5e72025-07-08 18:04:53 -04003444 /* Update the stacking order. 2nd panel will be on top */
3445 update_panels();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303446
micky3879b9f5e72025-07-08 18:04:53 -04003447 /* Show it on the screen */
3448 doupdate();
3449
3450 getch();
3451 endwin();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303452}
micky3879b9f5e72025-07-08 18:04:53 -04003453</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 &lt;string.h&gt;
3481#include &lt;panel.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303482
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()
micky3879b9f5e72025-07-08 18:04:53 -04003491{ WINDOW *my_wins[3];
3492 PANEL *my_panels[3];
3493 PANEL *top;
3494 int ch;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303495
micky3879b9f5e72025-07-08 18:04:53 -04003496 /* Initialize curses */
3497 initscr();
3498 start_color();
3499 cbreak();
3500 noecho();
3501 keypad(stdscr, TRUE);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303502
micky3879b9f5e72025-07-08 18:04:53 -04003503 /* 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);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303508
micky3879b9f5e72025-07-08 18:04:53 -04003509 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 */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303515
micky3879b9f5e72025-07-08 18:04:53 -04003516 /* 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]);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303520
micky3879b9f5e72025-07-08 18:04:53 -04003521 /* Update the stacking order. 2nd panel will be on top */
3522 update_panels();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303523
micky3879b9f5e72025-07-08 18:04:53 -04003524 /* 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();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303529
micky3879b9f5e72025-07-08 18:04:53 -04003530 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;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303543}
3544
3545/* Put all the windows */
3546void init_wins(WINDOW **wins, int n)
micky3879b9f5e72025-07-08 18:04:53 -04003547{ int x, y, i;
3548 char label[80];
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303549
micky3879b9f5e72025-07-08 18:04:53 -04003550 y = 2;
3551 x = 10;
3552 for(i = 0; i &lt; 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 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303559}
3560
3561/* Show the window with a border and a label */
3562void win_show(WINDOW *win, char *label, int label_color)
micky3879b9f5e72025-07-08 18:04:53 -04003563{ int startx, starty, height, width;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303564
micky3879b9f5e72025-07-08 18:04:53 -04003565 getbegyx(win, starty, startx);
3566 getmaxyx(win, height, width);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303567
micky3879b9f5e72025-07-08 18:04:53 -04003568 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));
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303574}
3575
3576void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color)
micky3879b9f5e72025-07-08 18:04:53 -04003577{ int length, x, y;
3578 float temp;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303579
micky3879b9f5e72025-07-08 18:04:53 -04003580 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;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303589
micky3879b9f5e72025-07-08 18:04:53 -04003590 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 &lt;TAB&gt; 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 &lt;stdlib.h&gt;
3659#include &lt;string.h&gt;
3660#include &lt;panel.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303661
3662typedef struct _PANEL_DATA {
micky3879b9f5e72025-07-08 18:04:53 -04003663 int x, y, w, h;
3664 char label[80];
3665 int label_color;
3666 PANEL *next;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303667}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()
micky3879b9f5e72025-07-08 18:04:53 -04003678{ 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;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303686
micky3879b9f5e72025-07-08 18:04:53 -04003687 /* Initialize curses */
3688 initscr();
3689 start_color();
3690 cbreak();
3691 noecho();
3692 keypad(stdscr, TRUE);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303693
micky3879b9f5e72025-07-08 18:04:53 -04003694 /* 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);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303699
micky3879b9f5e72025-07-08 18:04:53 -04003700 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 */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303706
micky3879b9f5e72025-07-08 18:04:53 -04003707 set_user_ptrs(my_panels, 3);
3708 /* Update the stacking order. 2nd panel will be on top */
3709 update_panels();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303710
micky3879b9f5e72025-07-08 18:04:53 -04003711 /* 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();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303717
micky3879b9f5e72025-07-08 18:04:53 -04003718 stack_top = my_panels[2];
3719 top = (PANEL_DATA *)panel_userptr(stack_top);
3720 newx = top-&gt;x;
3721 newy = top-&gt;y;
3722 neww = top-&gt;w;
3723 newh = top-&gt;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-&gt;next);
3729 stack_top = top-&gt;next;
3730 top = (PANEL_DATA *)panel_userptr(stack_top);
3731 newx = top-&gt;x;
3732 newy = top-&gt;y;
3733 neww = top-&gt;w;
3734 newh = top-&gt;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 &lt;ENTER&gt; 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 &lt;ENTER&gt; 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-&gt;label, top-&gt;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;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303811}
3812
3813/* Put all the windows */
3814void init_wins(WINDOW **wins, int n)
micky3879b9f5e72025-07-08 18:04:53 -04003815{ int x, y, i;
3816 char label[80];
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303817
micky3879b9f5e72025-07-08 18:04:53 -04003818 y = 2;
3819 x = 10;
3820 for(i = 0; i &lt; 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 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303827}
3828
3829/* Set the PANEL_DATA structures for individual panels */
3830void set_user_ptrs(PANEL **panels, int n)
micky3879b9f5e72025-07-08 18:04:53 -04003831{ 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));
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303837
micky3879b9f5e72025-07-08 18:04:53 -04003838 for(i = 0;i &lt; 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], &amp;ptrs[i]);
3854 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303855}
3856
3857/* Show the window with a border and a label */
3858void win_show(WINDOW *win, char *label, int label_color)
micky3879b9f5e72025-07-08 18:04:53 -04003859{ int startx, starty, height, width;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303860
micky3879b9f5e72025-07-08 18:04:53 -04003861 getbegyx(win, starty, startx);
3862 getmaxyx(win, height, width);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303863
micky3879b9f5e72025-07-08 18:04:53 -04003864 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));
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303870}
3871
3872void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color)
micky3879b9f5e72025-07-08 18:04:53 -04003873{ int length, x, y;
3874 float temp;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303875
micky3879b9f5e72025-07-08 18:04:53 -04003876 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;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303885
micky3879b9f5e72025-07-08 18:04:53 -04003886 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 &lt;ENTER&gt; 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 &lt;ENTER&gt;
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 &lt;string.h&gt;
3952#include &lt;panel.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303953
3954typedef struct _PANEL_DATA {
micky3879b9f5e72025-07-08 18:04:53 -04003955 int hide; /* TRUE if panel is hidden */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303956}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()
micky3879b9f5e72025-07-08 18:04:53 -04003966{ WINDOW *my_wins[3];
3967 PANEL *my_panels[3];
3968 PANEL_DATA panel_datas[3];
3969 PANEL_DATA *temp;
3970 int ch;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303971
micky3879b9f5e72025-07-08 18:04:53 -04003972 /* Initialize curses */
3973 initscr();
3974 start_color();
3975 cbreak();
3976 noecho();
3977 keypad(stdscr, TRUE);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303978
micky3879b9f5e72025-07-08 18:04:53 -04003979 /* 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);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303984
micky3879b9f5e72025-07-08 18:04:53 -04003985 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 */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303991
micky3879b9f5e72025-07-08 18:04:53 -04003992 /* 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;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05303996
micky3879b9f5e72025-07-08 18:04:53 -04003997 set_panel_userptr(my_panels[0], &amp;panel_datas[0]);
3998 set_panel_userptr(my_panels[1], &amp;panel_datas[1]);
3999 set_panel_userptr(my_panels[2], &amp;panel_datas[2]);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304000
micky3879b9f5e72025-07-08 18:04:53 -04004001 /* Update the stacking order. 2nd panel will be on top */
4002 update_panels();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304003
micky3879b9f5e72025-07-08 18:04:53 -04004004 /* 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");
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304008
micky3879b9f5e72025-07-08 18:04:53 -04004009 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-&gt;hide == FALSE)
4017 { hide_panel(my_panels[0]);
4018 temp-&gt;hide = TRUE;
4019 }
4020 else
4021 { show_panel(my_panels[0]);
4022 temp-&gt;hide = FALSE;
4023 }
4024 break;
4025 case 'b':
4026 temp = (PANEL_DATA *)panel_userptr(my_panels[1]);
4027 if(temp-&gt;hide == FALSE)
4028 { hide_panel(my_panels[1]);
4029 temp-&gt;hide = TRUE;
4030 }
4031 else
4032 { show_panel(my_panels[1]);
4033 temp-&gt;hide = FALSE;
4034 }
4035 break;
4036 case 'c':
4037 temp = (PANEL_DATA *)panel_userptr(my_panels[2]);
4038 if(temp-&gt;hide == FALSE)
4039 { hide_panel(my_panels[2]);
4040 temp-&gt;hide = TRUE;
4041 }
4042 else
4043 { show_panel(my_panels[2]);
4044 temp-&gt;hide = FALSE;
4045 }
4046 break;
4047 }
4048 update_panels();
4049 doupdate();
4050 }
4051 endwin();
4052 return 0;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304053}
4054
4055/* Put all the windows */
4056void init_wins(WINDOW **wins, int n)
micky3879b9f5e72025-07-08 18:04:53 -04004057{ int x, y, i;
4058 char label[80];
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304059
micky3879b9f5e72025-07-08 18:04:53 -04004060 y = 2;
4061 x = 10;
4062 for(i = 0; i &lt; 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 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304069}
4070
4071/* Show the window with a border and a label */
4072void win_show(WINDOW *win, char *label, int label_color)
micky3879b9f5e72025-07-08 18:04:53 -04004073{ int startx, starty, height, width;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304074
micky3879b9f5e72025-07-08 18:04:53 -04004075 getbegyx(win, starty, startx);
4076 getmaxyx(win, height, width);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304077
micky3879b9f5e72025-07-08 18:04:53 -04004078 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));
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304084}
4085
4086void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color)
micky3879b9f5e72025-07-08 18:04:53 -04004087{ int length, x, y;
4088 float temp;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304089
micky3879b9f5e72025-07-08 18:04:53 -04004090 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;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304099
micky3879b9f5e72025-07-08 18:04:53 -04004100 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 &lt;menu.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304220 .
4221 .
4222 .
4223
micky3879b9f5e72025-07-08 18:04:53 -04004224 compile and link: gcc &lt;program file&gt; -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 &lt;stdlib.h&gt;
4232#include &lt;curses.h&gt;
4233#include &lt;menu.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304234
4235#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
micky3879b9f5e72025-07-08 18:04:53 -04004236#define CTRLD 4
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304237
4238char *choices[] = {
4239 "Choice 1",
4240 "Choice 2",
4241 "Choice 3",
4242 "Choice 4",
4243 "Exit",
4244 };
4245
4246int main()
micky3879b9f5e72025-07-08 18:04:53 -04004247{ 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 *));
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304261
micky3879b9f5e72025-07-08 18:04:53 -04004262 for(i = 0; i &lt; n_choices; ++i)
4263 my_items[i] = new_item(choices[i], choices[i]);
4264 my_items[n_choices] = (ITEM *)NULL;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304265
micky3879b9f5e72025-07-08 18:04:53 -04004266 my_menu = new_menu((ITEM **)my_items);
4267 mvprintw(LINES - 2, 0, "F1 to Exit");
4268 post_menu(my_menu);
4269 refresh();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304270
micky3879b9f5e72025-07-08 18:04:53 -04004271 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 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304281
micky3879b9f5e72025-07-08 18:04:53 -04004282 free_item(my_items[0]);
4283 free_item(my_items[1]);
4284 free_menu(my_menu);
4285 endwin();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304286}
micky3879b9f5e72025-07-08 18:04:53 -04004287 </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">&#13; REQ_LEFT_ITEM Move left to an item.
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304308 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.
micky3879b9f5e72025-07-08 18:04:53 -04004323 REQ_PREV_MATCH Move to the previous item matching the pattern match.&#13;</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
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304438 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&shy;
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,
micky3879b9f5e72025-07-08 18:04:53 -04004449 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 &lt;stdlib.h&gt;
4482#include &lt;string.h&gt;
4483#include &lt;menu.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304484
4485#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
micky3879b9f5e72025-07-08 18:04:53 -04004486#define CTRLD 4
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304487
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()
micky3879b9f5e72025-07-08 18:04:53 -04004499{ ITEM **my_items;
4500 int c;
4501 MENU *my_menu;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304502 WINDOW *my_menu_win;
4503 int n_choices, i;
micky3879b9f5e72025-07-08 18:04:53 -04004504
4505 /* Initialize curses */
4506 initscr();
4507 start_color();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304508 cbreak();
4509 noecho();
micky3879b9f5e72025-07-08 18:04:53 -04004510 keypad(stdscr, TRUE);
4511 init_pair(1, COLOR_RED, COLOR_BLACK);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304512
micky3879b9f5e72025-07-08 18:04:53 -04004513 /* Create items */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304514 n_choices = ARRAY_SIZE(choices);
4515 my_items = (ITEM **)calloc(n_choices, sizeof(ITEM *));
micky3879b9f5e72025-07-08 18:04:53 -04004516 for(i = 0; i &lt; n_choices; ++i)
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304517 my_items[i] = new_item(choices[i], choices[i]);
4518
micky3879b9f5e72025-07-08 18:04:53 -04004519 /* Create menu */
4520 my_menu = new_menu((ITEM **)my_items);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304521
micky3879b9f5e72025-07-08 18:04:53 -04004522 /* Create the window to be associated with the menu */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304523 my_menu_win = newwin(10, 40, 4, 4);
4524 keypad(my_menu_win, TRUE);
4525
micky3879b9f5e72025-07-08 18:04:53 -04004526 /* Set main window and sub window */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304527 set_menu_win(my_menu, my_menu_win);
4528 set_menu_sub(my_menu, derwin(my_menu_win, 6, 38, 3, 1));
4529
micky3879b9f5e72025-07-08 18:04:53 -04004530 /* Set menu mark to the string " * " */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304531 set_menu_mark(my_menu, " * ");
4532
micky3879b9f5e72025-07-08 18:04:53 -04004533 /* Print a border around the main window and print a title */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304534 box(my_menu_win, 0, 0);
micky3879b9f5e72025-07-08 18:04:53 -04004535 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();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304541
micky3879b9f5e72025-07-08 18:04:53 -04004542 /* Post the menu */
4543 post_menu(my_menu);
4544 wrefresh(my_menu_win);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304545
micky3879b9f5e72025-07-08 18:04:53 -04004546 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 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304555 wrefresh(my_menu_win);
micky3879b9f5e72025-07-08 18:04:53 -04004556 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304557
micky3879b9f5e72025-07-08 18:04:53 -04004558 /* Unpost and free all the memory taken up */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304559 unpost_menu(my_menu);
4560 free_menu(my_menu);
micky3879b9f5e72025-07-08 18:04:53 -04004561 for(i = 0; i &lt; n_choices; ++i)
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304562 free_item(my_items[i]);
micky3879b9f5e72025-07-08 18:04:53 -04004563 endwin();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304564}
4565
4566void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color)
micky3879b9f5e72025-07-08 18:04:53 -04004567{ int length, x, y;
4568 float temp;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304569
micky3879b9f5e72025-07-08 18:04:53 -04004570 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;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304579
micky3879b9f5e72025-07-08 18:04:53 -04004580 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 &lt;stdlib.h&gt;
4620#include &lt;string.h&gt;
4621#include &lt;curses.h&gt;
4622#include &lt;menu.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304623
4624#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
micky3879b9f5e72025-07-08 18:04:53 -04004625#define CTRLD 4
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304626
4627char *choices[] = {
4628 "Choice 1",
4629 "Choice 2",
4630 "Choice 3",
4631 "Choice 4",
micky3879b9f5e72025-07-08 18:04:53 -04004632 "Choice 5",
4633 "Choice 6",
4634 "Choice 7",
4635 "Choice 8",
4636 "Choice 9",
4637 "Choice 10",
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304638 "Exit",
4639 (char *)NULL,
4640 };
4641void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color);
4642
4643int main()
micky3879b9f5e72025-07-08 18:04:53 -04004644{ ITEM **my_items;
4645 int c;
4646 MENU *my_menu;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304647 WINDOW *my_menu_win;
4648 int n_choices, i;
micky3879b9f5e72025-07-08 18:04:53 -04004649
4650 /* Initialize curses */
4651 initscr();
4652 start_color();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304653 cbreak();
4654 noecho();
micky3879b9f5e72025-07-08 18:04:53 -04004655 keypad(stdscr, TRUE);
4656 init_pair(1, COLOR_RED, COLOR_BLACK);
4657 init_pair(2, COLOR_CYAN, COLOR_BLACK);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304658
micky3879b9f5e72025-07-08 18:04:53 -04004659 /* Create items */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304660 n_choices = ARRAY_SIZE(choices);
4661 my_items = (ITEM **)calloc(n_choices, sizeof(ITEM *));
micky3879b9f5e72025-07-08 18:04:53 -04004662 for(i = 0; i &lt; n_choices; ++i)
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304663 my_items[i] = new_item(choices[i], choices[i]);
4664
micky3879b9f5e72025-07-08 18:04:53 -04004665 /* Create menu */
4666 my_menu = new_menu((ITEM **)my_items);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304667
micky3879b9f5e72025-07-08 18:04:53 -04004668 /* Create the window to be associated with the menu */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304669 my_menu_win = newwin(10, 40, 4, 4);
4670 keypad(my_menu_win, TRUE);
4671
micky3879b9f5e72025-07-08 18:04:53 -04004672 /* Set main window and sub window */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304673 set_menu_win(my_menu, my_menu_win);
4674 set_menu_sub(my_menu, derwin(my_menu_win, 6, 38, 3, 1));
micky3879b9f5e72025-07-08 18:04:53 -04004675 set_menu_format(my_menu, 5, 1);
4676
4677 /* Set menu mark to the string " * " */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304678 set_menu_mark(my_menu, " * ");
4679
micky3879b9f5e72025-07-08 18:04:53 -04004680 /* Print a border around the main window and print a title */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304681 box(my_menu_win, 0, 0);
micky3879b9f5e72025-07-08 18:04:53 -04004682 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);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304686
micky3879b9f5e72025-07-08 18:04:53 -04004687 /* 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();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304696
micky3879b9f5e72025-07-08 18:04:53 -04004697 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 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304712 wrefresh(my_menu_win);
micky3879b9f5e72025-07-08 18:04:53 -04004713 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304714
micky3879b9f5e72025-07-08 18:04:53 -04004715 /* Unpost and free all the memory taken up */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304716 unpost_menu(my_menu);
4717 free_menu(my_menu);
micky3879b9f5e72025-07-08 18:04:53 -04004718 for(i = 0; i &lt; n_choices; ++i)
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304719 free_item(my_items[i]);
micky3879b9f5e72025-07-08 18:04:53 -04004720 endwin();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304721}
4722
4723void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color)
micky3879b9f5e72025-07-08 18:04:53 -04004724{ int length, x, y;
4725 float temp;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304726
micky3879b9f5e72025-07-08 18:04:53 -04004727 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;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304736
micky3879b9f5e72025-07-08 18:04:53 -04004737 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 &lt;stdlib.h&gt;
4782#include &lt;curses.h&gt;
4783#include &lt;menu.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304784
4785#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
micky3879b9f5e72025-07-08 18:04:53 -04004786#define CTRLD 4
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304787
4788char *choices[] = {
4789 "Choice 1", "Choice 2", "Choice 3", "Choice 4", "Choice 5",
micky3879b9f5e72025-07-08 18:04:53 -04004790 "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",
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304793 "Exit",
4794 (char *)NULL,
4795 };
4796
4797int main()
micky3879b9f5e72025-07-08 18:04:53 -04004798{ ITEM **my_items;
4799 int c;
4800 MENU *my_menu;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304801 WINDOW *my_menu_win;
4802 int n_choices, i;
micky3879b9f5e72025-07-08 18:04:53 -04004803
4804 /* Initialize curses */
4805 initscr();
4806 start_color();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304807 cbreak();
4808 noecho();
micky3879b9f5e72025-07-08 18:04:53 -04004809 keypad(stdscr, TRUE);
4810 init_pair(1, COLOR_RED, COLOR_BLACK);
4811 init_pair(2, COLOR_CYAN, COLOR_BLACK);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304812
micky3879b9f5e72025-07-08 18:04:53 -04004813 /* Create items */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304814 n_choices = ARRAY_SIZE(choices);
4815 my_items = (ITEM **)calloc(n_choices, sizeof(ITEM *));
micky3879b9f5e72025-07-08 18:04:53 -04004816 for(i = 0; i &lt; n_choices; ++i)
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304817 my_items[i] = new_item(choices[i], choices[i]);
4818
micky3879b9f5e72025-07-08 18:04:53 -04004819 /* Create menu */
4820 my_menu = new_menu((ITEM **)my_items);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304821
micky3879b9f5e72025-07-08 18:04:53 -04004822 /* Set menu option not to show the description */
4823 menu_opts_off(my_menu, O_SHOWDESC);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304824
micky3879b9f5e72025-07-08 18:04:53 -04004825 /* Create the window to be associated with the menu */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304826 my_menu_win = newwin(10, 70, 4, 4);
4827 keypad(my_menu_win, TRUE);
4828
micky3879b9f5e72025-07-08 18:04:53 -04004829 /* Set main window and sub window */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304830 set_menu_win(my_menu, my_menu_win);
4831 set_menu_sub(my_menu, derwin(my_menu_win, 6, 68, 3, 1));
micky3879b9f5e72025-07-08 18:04:53 -04004832 set_menu_format(my_menu, 5, 3);
4833 set_menu_mark(my_menu, " * ");
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304834
micky3879b9f5e72025-07-08 18:04:53 -04004835 /* Print a border around the main window and print a title */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304836 box(my_menu_win, 0, 0);
micky3879b9f5e72025-07-08 18:04:53 -04004837
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();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304843
micky3879b9f5e72025-07-08 18:04:53 -04004844 /* 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 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304869 wrefresh(my_menu_win);
micky3879b9f5e72025-07-08 18:04:53 -04004870 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304871
micky3879b9f5e72025-07-08 18:04:53 -04004872 /* Unpost and free all the memory taken up */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304873 unpost_menu(my_menu);
4874 free_menu(my_menu);
micky3879b9f5e72025-07-08 18:04:53 -04004875 for(i = 0; i &lt; n_choices; ++i)
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304876 free_item(my_items[i]);
micky3879b9f5e72025-07-08 18:04:53 -04004877 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
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304890 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&shy;
4904 tern-matching.
4905
4906 O_NONCYCLIC
4907 Don't wrap around next-item and previous-item,
micky3879b9f5e72025-07-08 18:04:53 -04004908 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 &lt;stdlib.h&gt;
4936#include &lt;string.h&gt;
4937#include &lt;curses.h&gt;
4938#include &lt;menu.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304939
4940#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
micky3879b9f5e72025-07-08 18:04:53 -04004941#define CTRLD 4
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304942
4943char *choices[] = {
4944 "Choice 1",
4945 "Choice 2",
4946 "Choice 3",
4947 "Choice 4",
micky3879b9f5e72025-07-08 18:04:53 -04004948 "Choice 5",
4949 "Choice 6",
4950 "Choice 7",
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304951 "Exit",
4952 };
4953
4954int main()
micky3879b9f5e72025-07-08 18:04:53 -04004955{ ITEM **my_items;
4956 int c;
4957 MENU *my_menu;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304958 int n_choices, i;
micky3879b9f5e72025-07-08 18:04:53 -04004959 ITEM *cur_item;
4960
4961 /* Initialize curses */
4962 initscr();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304963 cbreak();
4964 noecho();
micky3879b9f5e72025-07-08 18:04:53 -04004965 keypad(stdscr, TRUE);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304966
micky3879b9f5e72025-07-08 18:04:53 -04004967 /* Initialize items */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304968 n_choices = ARRAY_SIZE(choices);
4969 my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *));
micky3879b9f5e72025-07-08 18:04:53 -04004970 for(i = 0; i &lt; n_choices; ++i)
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304971 my_items[i] = new_item(choices[i], choices[i]);
micky3879b9f5e72025-07-08 18:04:53 -04004972 my_items[n_choices] = (ITEM *)NULL;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304973
micky3879b9f5e72025-07-08 18:04:53 -04004974 my_menu = new_menu((ITEM **)my_items);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304975
micky3879b9f5e72025-07-08 18:04:53 -04004976 /* Make the menu multi valued */
4977 menu_opts_off(my_menu, O_ONEVALUE);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304978
micky3879b9f5e72025-07-08 18:04:53 -04004979 mvprintw(LINES - 3, 0, "Use &lt;SPACE&gt; to select or unselect an item.");
4980 mvprintw(LINES - 2, 0, "&lt;ENTER&gt; to see presently selected items(F1 to Exit)");
4981 post_menu(my_menu);
4982 refresh();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304983
micky3879b9f5e72025-07-08 18:04:53 -04004984 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;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304998
micky3879b9f5e72025-07-08 18:04:53 -04004999 items = menu_items(my_menu);
5000 temp[0] = '\0';
5001 for(i = 0; i &lt; 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 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305014
micky3879b9f5e72025-07-08 18:04:53 -04005015 free_item(my_items[0]);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305016 free_item(my_items[1]);
micky3879b9f5e72025-07-08 18:04:53 -04005017 free_menu(my_menu);
5018 endwin();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305019}
micky3879b9f5e72025-07-08 18:04:53 -04005020 </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 &lt;ENTER&gt; 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 &lt;stdlib.h&gt;
5075#include &lt;menu.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305076
5077#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
micky3879b9f5e72025-07-08 18:04:53 -04005078#define CTRLD 4
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305079
5080char *choices[] = {
5081 "Choice 1",
5082 "Choice 2",
5083 "Choice 3",
5084 "Choice 4",
micky3879b9f5e72025-07-08 18:04:53 -04005085 "Choice 5",
5086 "Choice 6",
5087 "Choice 7",
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305088 "Exit",
5089 };
5090
5091int main()
micky3879b9f5e72025-07-08 18:04:53 -04005092{ ITEM **my_items;
5093 int c;
5094 MENU *my_menu;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305095 int n_choices, i;
micky3879b9f5e72025-07-08 18:04:53 -04005096 ITEM *cur_item;
5097
5098 /* Initialize curses */
5099 initscr();
5100 start_color();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305101 cbreak();
5102 noecho();
micky3879b9f5e72025-07-08 18:04:53 -04005103 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);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305107
micky3879b9f5e72025-07-08 18:04:53 -04005108 /* Initialize items */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305109 n_choices = ARRAY_SIZE(choices);
5110 my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *));
micky3879b9f5e72025-07-08 18:04:53 -04005111 for(i = 0; i &lt; n_choices; ++i)
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305112 my_items[i] = new_item(choices[i], choices[i]);
micky3879b9f5e72025-07-08 18:04:53 -04005113 my_items[n_choices] = (ITEM *)NULL;
5114 item_opts_off(my_items[3], O_SELECTABLE);
5115 item_opts_off(my_items[6], O_SELECTABLE);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305116
micky3879b9f5e72025-07-08 18:04:53 -04005117 /* Create menu */
5118 my_menu = new_menu((ITEM **)my_items);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305119
micky3879b9f5e72025-07-08 18:04:53 -04005120 /* 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));
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305124
micky3879b9f5e72025-07-08 18:04:53 -04005125 /* Post the menu */
5126 mvprintw(LINES - 3, 0, "Press &lt;ENTER&gt; 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();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305130
micky3879b9f5e72025-07-08 18:04:53 -04005131 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 &lt; n_choices; ++i)
5150 free_item(my_items[i]);
5151 free_menu(my_menu);
5152 endwin();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305153}
micky3879b9f5e72025-07-08 18:04:53 -04005154 </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 &lt;ENTER&gt;);</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 &lt;stdlib.h&gt;
5178#include &lt;curses.h&gt;
5179#include &lt;menu.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305180
5181#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
micky3879b9f5e72025-07-08 18:04:53 -04005182#define CTRLD 4
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305183
5184char *choices[] = {
5185 "Choice 1",
5186 "Choice 2",
5187 "Choice 3",
5188 "Choice 4",
micky3879b9f5e72025-07-08 18:04:53 -04005189 "Choice 5",
5190 "Choice 6",
5191 "Choice 7",
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305192 "Exit",
5193 };
5194void func(char *name);
5195
5196int main()
micky3879b9f5e72025-07-08 18:04:53 -04005197{ ITEM **my_items;
5198 int c;
5199 MENU *my_menu;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305200 int n_choices, i;
micky3879b9f5e72025-07-08 18:04:53 -04005201 ITEM *cur_item;
5202
5203 /* Initialize curses */
5204 initscr();
5205 start_color();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305206 cbreak();
5207 noecho();
micky3879b9f5e72025-07-08 18:04:53 -04005208 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);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305212
micky3879b9f5e72025-07-08 18:04:53 -04005213 /* Initialize items */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305214 n_choices = ARRAY_SIZE(choices);
5215 my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *));
micky3879b9f5e72025-07-08 18:04:53 -04005216 for(i = 0; i &lt; 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;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305222
micky3879b9f5e72025-07-08 18:04:53 -04005223 /* Create menu */
5224 my_menu = new_menu((ITEM **)my_items);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305225
micky3879b9f5e72025-07-08 18:04:53 -04005226 /* Post the menu */
5227 mvprintw(LINES - 3, 0, "Press &lt;ENTER&gt; 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();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305231
micky3879b9f5e72025-07-08 18:04:53 -04005232 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 *);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305243
micky3879b9f5e72025-07-08 18:04:53 -04005244 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 &lt; n_choices; ++i)
5255 free_item(my_items[i]);
5256 free_menu(my_menu);
5257 endwin();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305258}
5259
5260void func(char *name)
micky3879b9f5e72025-07-08 18:04:53 -04005261{ move(20, 0);
5262 clrtoeol();
5263 mvprintw(20, 0, "Item selected is : %s", name);
5264} </span></pre>
5265 </div>
5266 </div>
5267 </div>
Steve Kondikae271bc2015-11-15 02:50:53 +01005268
micky3879b9f5e72025-07-08 18:04:53 -04005269 <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 &lt;form.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305374 .
5375 .
5376 .
5377
micky3879b9f5e72025-07-08 18:04:53 -04005378 compile and link: gcc &lt;program file&gt; -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 &lt;form.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305386
5387int main()
micky3879b9f5e72025-07-08 18:04:53 -04005388{ FIELD *field[3];
5389 FORM *my_form;
5390 int ch;
5391
5392 /* Initialize curses */
5393 initscr();
5394 cbreak();
5395 noecho();
5396 keypad(stdscr, TRUE);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305397
micky3879b9f5e72025-07-08 18:04:53 -04005398 /* 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;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305402
micky3879b9f5e72025-07-08 18:04:53 -04005403 /* 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);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305409
micky3879b9f5e72025-07-08 18:04:53 -04005410 /* 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();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305418
micky3879b9f5e72025-07-08 18:04:53 -04005419 /* 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 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305441
micky3879b9f5e72025-07-08 18:04:53 -04005442 /* 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]);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305447
micky3879b9f5e72025-07-08 18:04:53 -04005448 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 */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305505 int *height, *int width, /* field size */
5506 int *top, int *left, /* upper left corner */
5507 int *offscreen, /* number of offscreen rows */
micky3879b9f5e72025-07-08 18:04:53 -04005508 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 */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305538 int justmode); /* mode to set */
micky3879b9f5e72025-07-08 18:04:53 -04005539 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">&#13;int set_field_fore(FIELD *field, /* field to alter */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305565 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 */
micky3879b9f5e72025-07-08 18:04:53 -04005580 /* returns present pad character */&#13;</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 &lt;form.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305601
5602int main()
micky3879b9f5e72025-07-08 18:04:53 -04005603{ 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);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305613
micky3879b9f5e72025-07-08 18:04:53 -04005614 /* Initialize few color pairs */
5615 init_pair(1, COLOR_WHITE, COLOR_BLUE);
5616 init_pair(2, COLOR_WHITE, COLOR_BLUE);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305617
micky3879b9f5e72025-07-08 18:04:53 -04005618 /* 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;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305622
micky3879b9f5e72025-07-08 18:04:53 -04005623 /* 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);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305631
micky3879b9f5e72025-07-08 18:04:53 -04005632 /* 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();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305642
micky3879b9f5e72025-07-08 18:04:53 -04005643 /* 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 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305665
micky3879b9f5e72025-07-08 18:04:53 -04005666 /* 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]);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305671
micky3879b9f5e72025-07-08 18:04:53 -04005672 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 */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305697 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
micky3879b9f5e72025-07-08 18:04:53 -04005705int 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 &lt;form.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305838
5839#define STARTX 15
5840#define STARTY 4
5841#define WIDTH 25
5842
5843#define N_FIELDS 3
5844
5845int main()
micky3879b9f5e72025-07-08 18:04:53 -04005846{ 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);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305855
micky3879b9f5e72025-07-08 18:04:53 -04005856 /* Initialize the fields */
5857 for(i = 0; i &lt; N_FIELDS - 1; ++i)
5858 field[i] = new_field(1, WIDTH, STARTY + i * 2, STARTX, 0, 0);
5859 field[N_FIELDS - 1] = NULL;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305860
micky3879b9f5e72025-07-08 18:04:53 -04005861 /* 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();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305880
micky3879b9f5e72025-07-08 18:04:53 -04005881 /* 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 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305903
micky3879b9f5e72025-07-08 18:04:53 -04005904 /* 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]);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305909
micky3879b9f5e72025-07-08 18:04:53 -04005910 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 */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305937 int status); /* status to set */
5938
micky3879b9f5e72025-07-08 18:04:53 -04005939int 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,
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05305965 char *userptr); /* the user pointer you wish to associate */
5966 /* with the field */
5967
micky3879b9f5e72025-07-08 18:04:53 -04005968char *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 */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05306003 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 */
micky3879b9f5e72025-07-08 18:04:53 -04006006 /* 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 &lt;string.h&gt;
6133#include &lt;form.h&gt;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05306134
6135void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color);
6136
6137int main()
6138{
micky3879b9f5e72025-07-08 18:04:53 -04006139 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);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05306150
micky3879b9f5e72025-07-08 18:04:53 -04006151 /* Initialize few color pairs */
6152 init_pair(1, COLOR_RED, COLOR_BLACK);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05306153
micky3879b9f5e72025-07-08 18:04:53 -04006154 /* 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;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05306158
micky3879b9f5e72025-07-08 18:04:53 -04006159 /* 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, &amp;rows, &amp;cols);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05306171
micky3879b9f5e72025-07-08 18:04:53 -04006172 /* Create the window to be associated with the form */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05306173 my_form_win = newwin(rows + 4, cols + 4, 4, 4);
6174 keypad(my_form_win, TRUE);
6175
micky3879b9f5e72025-07-08 18:04:53 -04006176 /* Set main window and sub window */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05306177 set_form_win(my_form, my_form_win);
6178 set_form_sub(my_form, derwin(my_form_win, rows, cols, 2, 2));
6179
micky3879b9f5e72025-07-08 18:04:53 -04006180 /* Print a border around the main window and print a title */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05306181 box(my_form_win, 0, 0);
micky3879b9f5e72025-07-08 18:04:53 -04006182 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);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05306186
micky3879b9f5e72025-07-08 18:04:53 -04006187 mvprintw(LINES - 2, 0, "Use UP, DOWN arrow keys to switch between fields");
6188 refresh();
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05306189
micky3879b9f5e72025-07-08 18:04:53 -04006190 /* 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 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05306212
micky3879b9f5e72025-07-08 18:04:53 -04006213 /* 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]);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05306218
micky3879b9f5e72025-07-08 18:04:53 -04006219 endwin();
6220 return 0;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05306221}
6222
6223void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color)
micky3879b9f5e72025-07-08 18:04:53 -04006224{ int length, x, y;
6225 float temp;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05306226
micky3879b9f5e72025-07-08 18:04:53 -04006227 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;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05306236
micky3879b9f5e72025-07-08 18:04:53 -04006237 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 */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05306267 FIELDTYPE *ftype, /* type to associate */
micky3879b9f5e72025-07-08 18:04:53 -04006268 ...); /* 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 */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05306302 TYPE_ALPHA, /* type to associate */
micky3879b9f5e72025-07-08 18:04:53 -04006303 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 */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05306320 TYPE_ALNUM, /* type to associate */
micky3879b9f5e72025-07-08 18:04:53 -04006321 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 */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05306338 TYPE_ENUM, /* type to associate */
6339 char **valuelist; /* list of possible values */
6340 int checkcase; /* case-sensitive? */
micky3879b9f5e72025-07-08 18:04:53 -04006341 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 */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05306369 TYPE_INTEGER, /* type to associate */
6370 int padding, /* # places to zero-pad to */
micky3879b9f5e72025-07-08 18:04:53 -04006371 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 */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05306392 TYPE_NUMERIC, /* type to associate */
6393 int padding, /* # places of precision */
micky3879b9f5e72025-07-08 18:04:53 -04006394 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 */
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05306415 TYPE_REGEXP, /* type to associate */
micky3879b9f5e72025-07-08 18:04:53 -04006416 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
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05307033===========================================================================
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.
micky3879b9f5e72025-07-08 18:04:53 -04007075===========================================================================</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">"&lt;/B/1&gt;This line should have a yellow foreground and a blue
7096background.&lt;!1&gt;"</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
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05307222are 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
micky3879b9f5e72025-07-08 18:04:53 -04007226only 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>