1262685Sdelphij<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
2262685Sdelphij<HTML
3262685Sdelphij><HEAD
4262685Sdelphij><TITLE
5262685Sdelphij> NCURSES Programming HOWTO </TITLE
6262685Sdelphij><META
7262685SdelphijNAME="GENERATOR"
8262685SdelphijCONTENT="Modular DocBook HTML Stylesheet Version 1.79"></HEAD
9262685Sdelphij><BODY
10262685SdelphijCLASS="ARTICLE"
11262685SdelphijBGCOLOR="#FFFFFF"
12262685SdelphijTEXT="#000000"
13262685SdelphijLINK="#0000FF"
14262685SdelphijVLINK="#840084"
15262685SdelphijALINK="#0000FF"
16262685Sdelphij><DIV
17262685SdelphijCLASS="ARTICLE"
18262685Sdelphij><DIV
19262685SdelphijCLASS="TITLEPAGE"
20262685Sdelphij><H1
21262685SdelphijCLASS="TITLE"
22262685Sdelphij><A
23262685SdelphijNAME="AEN2"
24262685Sdelphij>NCURSES Programming HOWTO</A
25262685Sdelphij></H1
26262685Sdelphij><H3
27262685SdelphijCLASS="AUTHOR"
28262685Sdelphij><A
29262685SdelphijNAME="AEN4"
30262685Sdelphij> Pradeep   Padala </A
31262685Sdelphij></H3
32262685Sdelphij><DIV
33262685SdelphijCLASS="AFFILIATION"
34262685Sdelphij><DIV
35262685SdelphijCLASS="ADDRESS"
36262685Sdelphij><P
37262685SdelphijCLASS="ADDRESS"
38262685Sdelphij><CODE
39262685SdelphijCLASS="EMAIL"
40262685Sdelphij>&#60;<A
41262685SdelphijHREF="mailto:ppadala@gmail.com"
42262685Sdelphij>ppadala@gmail.com</A
43262685Sdelphij>&#62;</CODE
44262685Sdelphij></P
45262685Sdelphij></DIV
46262685Sdelphij></DIV
47262685Sdelphij><P
48262685SdelphijCLASS="PUBDATE"
49262685Sdelphij>v1.9, 2005-06-20<BR></P
50262685Sdelphij><DIV
51262685SdelphijCLASS="REVHISTORY"
52262685Sdelphij><TABLE
53262685SdelphijWIDTH="100%"
54262685SdelphijBORDER="0"
55262685Sdelphij><TR
56262685Sdelphij><TH
57262685SdelphijALIGN="LEFT"
58262685SdelphijVALIGN="TOP"
59262685SdelphijCOLSPAN="3"
60262685Sdelphij><B
61262685Sdelphij>Revision History</B
62262685Sdelphij></TH
63262685Sdelphij></TR
64262685Sdelphij><TR
65262685Sdelphij><TD
66262685SdelphijALIGN="LEFT"
67262685Sdelphij>Revision 1.9</TD
68262685Sdelphij><TD
69262685SdelphijALIGN="LEFT"
70262685Sdelphij>2005-06-20</TD
71262685Sdelphij><TD
72262685SdelphijALIGN="LEFT"
73262685Sdelphij>Revised by: ppadala</TD
74262685Sdelphij></TR
75262685Sdelphij><TR
76262685Sdelphij><TD
77262685SdelphijALIGN="LEFT"
78262685SdelphijCOLSPAN="3"
79262685Sdelphij>The license has been changed to the MIT-style license used
80262685Sdelphij        by NCURSES. Note that the programs are also re-licensed under this.</TD
81262685Sdelphij></TR
82262685Sdelphij><TR
83262685Sdelphij><TD
84262685SdelphijALIGN="LEFT"
85262685Sdelphij>Revision 1.8</TD
86262685Sdelphij><TD
87262685SdelphijALIGN="LEFT"
88262685Sdelphij>2005-06-17</TD
89262685Sdelphij><TD
90262685SdelphijALIGN="LEFT"
91262685Sdelphij>Revised by: ppadala</TD
92262685Sdelphij></TR
93262685Sdelphij><TR
94262685Sdelphij><TD
95262685SdelphijALIGN="LEFT"
96262685SdelphijCOLSPAN="3"
97262685Sdelphij>Lots of updates. Added references and perl examples.
98262685Sdelphij        Changes to examples. Many grammatical and stylistic changes to the
99262685Sdelphij        content. Changes to NCURSES history.</TD
100262685Sdelphij></TR
101262685Sdelphij><TR
102262685Sdelphij><TD
103262685SdelphijALIGN="LEFT"
104262685Sdelphij>Revision 1.7.1</TD
105262685Sdelphij><TD
106262685SdelphijALIGN="LEFT"
107262685Sdelphij>2002-06-25</TD
108262685Sdelphij><TD
109262685SdelphijALIGN="LEFT"
110262685Sdelphij>Revised by: ppadala</TD
111262685Sdelphij></TR
112262685Sdelphij><TR
113262685Sdelphij><TD
114262685SdelphijALIGN="LEFT"
115262685SdelphijCOLSPAN="3"
116262685Sdelphij>Added a README file for building and instructions
117262685Sdelphij        for building from source.</TD
118262685Sdelphij></TR
119262685Sdelphij><TR
120262685Sdelphij><TD
121262685SdelphijALIGN="LEFT"
122262685Sdelphij>Revision 1.7</TD
123262685Sdelphij><TD
124262685SdelphijALIGN="LEFT"
125262685Sdelphij>2002-06-25</TD
126262685Sdelphij><TD
127262685SdelphijALIGN="LEFT"
128262685Sdelphij>Revised by: ppadala</TD
129262685Sdelphij></TR
130262685Sdelphij><TR
131262685Sdelphij><TD
132262685SdelphijALIGN="LEFT"
133262685SdelphijCOLSPAN="3"
134262685Sdelphij>Added "Other formats" section and made a lot of fancy 
135262685Sdelphij        changes to the programs. Inlining of programs is gone.</TD
136262685Sdelphij></TR
137262685Sdelphij><TR
138262685Sdelphij><TD
139262685SdelphijALIGN="LEFT"
140262685Sdelphij>Revision 1.6.1</TD
141262685Sdelphij><TD
142262685SdelphijALIGN="LEFT"
143262685Sdelphij>2002-02-24</TD
144262685Sdelphij><TD
145262685SdelphijALIGN="LEFT"
146262685Sdelphij>Revised by: ppadala</TD
147262685Sdelphij></TR
148262685Sdelphij><TR
149262685Sdelphij><TD
150262685SdelphijALIGN="LEFT"
151262685SdelphijCOLSPAN="3"
152262685Sdelphij>Removed the old Changelog section, cleaned the makefiles</TD
153262685Sdelphij></TR
154262685Sdelphij><TR
155262685Sdelphij><TD
156262685SdelphijALIGN="LEFT"
157262685Sdelphij>Revision 1.6</TD
158262685Sdelphij><TD
159262685SdelphijALIGN="LEFT"
160262685Sdelphij>2002-02-16</TD
161262685Sdelphij><TD
162262685SdelphijALIGN="LEFT"
163262685Sdelphij>Revised by: ppadala</TD
164262685Sdelphij></TR
165262685Sdelphij><TR
166262685Sdelphij><TD
167262685SdelphijALIGN="LEFT"
168262685SdelphijCOLSPAN="3"
169262685Sdelphij>Corrected a lot of spelling mistakes, added ACS variables
170262685Sdelphij        section</TD
171262685Sdelphij></TR
172262685Sdelphij><TR
173262685Sdelphij><TD
174262685SdelphijALIGN="LEFT"
175262685Sdelphij>Revision 1.5</TD
176262685Sdelphij><TD
177262685SdelphijALIGN="LEFT"
178262685Sdelphij>2002-01-05</TD
179262685Sdelphij><TD
180262685SdelphijALIGN="LEFT"
181262685Sdelphij>Revised by: ppadala</TD
182262685Sdelphij></TR
183262685Sdelphij><TR
184262685Sdelphij><TD
185262685SdelphijALIGN="LEFT"
186262685SdelphijCOLSPAN="3"
187262685Sdelphij>Changed structure to present proper TOC</TD
188262685Sdelphij></TR
189262685Sdelphij><TR
190262685Sdelphij><TD
191262685SdelphijALIGN="LEFT"
192262685Sdelphij>Revision 1.3.1</TD
193262685Sdelphij><TD
194262685SdelphijALIGN="LEFT"
195262685Sdelphij>2001-07-26</TD
196262685Sdelphij><TD
197262685SdelphijALIGN="LEFT"
198262685Sdelphij>Revised by: ppadala</TD
199262685Sdelphij></TR
200262685Sdelphij><TR
201262685Sdelphij><TD
202262685SdelphijALIGN="LEFT"
203262685SdelphijCOLSPAN="3"
204262685Sdelphij>Corrected maintainers paragraph, Corrected stable release number</TD
205262685Sdelphij></TR
206262685Sdelphij><TR
207262685Sdelphij><TD
208262685SdelphijALIGN="LEFT"
209262685Sdelphij>Revision 1.3</TD
210262685Sdelphij><TD
211262685SdelphijALIGN="LEFT"
212262685Sdelphij>2001-07-24</TD
213262685Sdelphij><TD
214262685SdelphijALIGN="LEFT"
215262685Sdelphij>Revised by: ppadala</TD
216262685Sdelphij></TR
217262685Sdelphij><TR
218262685Sdelphij><TD
219262685SdelphijALIGN="LEFT"
220262685SdelphijCOLSPAN="3"
221262685Sdelphij>Added copyright notices to main document (LDP license)
222262685Sdelphij        and programs (GPL), Corrected
223262685Sdelphij        printw_example.</TD
224262685Sdelphij></TR
225262685Sdelphij><TR
226262685Sdelphij><TD
227262685SdelphijALIGN="LEFT"
228262685Sdelphij>Revision 1.2</TD
229262685Sdelphij><TD
230262685SdelphijALIGN="LEFT"
231262685Sdelphij>2001-06-05</TD
232262685Sdelphij><TD
233262685SdelphijALIGN="LEFT"
234262685Sdelphij>Revised by: ppadala</TD
235262685Sdelphij></TR
236262685Sdelphij><TR
237262685Sdelphij><TD
238262685SdelphijALIGN="LEFT"
239262685SdelphijCOLSPAN="3"
240262685Sdelphij>Incorporated ravi's changes. Mainly to introduction, menu, 
241262685Sdelphij        form, justforfun sections</TD
242262685Sdelphij></TR
243262685Sdelphij><TR
244262685Sdelphij><TD
245262685SdelphijALIGN="LEFT"
246262685Sdelphij>Revision 1.1</TD
247262685Sdelphij><TD
248262685SdelphijALIGN="LEFT"
249262685Sdelphij>2001-05-22</TD
250262685Sdelphij><TD
251262685SdelphijALIGN="LEFT"
252262685Sdelphij>Revised by: ppadala</TD
253262685Sdelphij></TR
254262685Sdelphij><TR
255262685Sdelphij><TD
256262685SdelphijALIGN="LEFT"
257262685SdelphijCOLSPAN="3"
258262685Sdelphij>Added "a word about window" section, Added scanw_example.</TD
259262685Sdelphij></TR
260262685Sdelphij></TABLE
261262685Sdelphij></DIV
262262685Sdelphij><DIV
263262685Sdelphij><DIV
264262685SdelphijCLASS="ABSTRACT"
265262685Sdelphij><P
266262685Sdelphij></P
267262685Sdelphij><A
268262685SdelphijNAME="AEN67"
269262685Sdelphij></A
270262685Sdelphij><P
271262685Sdelphij>    <SPAN
272262685SdelphijCLASS="emphasis"
273262685Sdelphij><I
274262685SdelphijCLASS="EMPHASIS"
275262685Sdelphij>This document is intended to be an "All in One" guide for programming with 
276262685Sdelphijncurses and its sister libraries. We graduate from a simple "Hello World" 
277262685Sdelphijprogram to more complex form manipulation. No prior experience in ncurses is 
278262685Sdelphijassumed. Send comments to <A
279262685SdelphijHREF="mailto:ppadala@gmail.com"
280262685SdelphijTARGET="_top"
281262685Sdelphij>this address</A
282262685Sdelphij>
283262685Sdelphij    </I
284262685Sdelphij></SPAN
285262685Sdelphij>
286262685Sdelphij    </P
287262685Sdelphij><P
288262685Sdelphij></P
289262685Sdelphij></DIV
290262685Sdelphij></DIV
291262685Sdelphij><HR></DIV
292262685Sdelphij><DIV
293262685SdelphijCLASS="TOC"
294262685Sdelphij><DL
295262685Sdelphij><DT
296262685Sdelphij><B
297262685Sdelphij>Table of Contents</B
298262685Sdelphij></DT
299262685Sdelphij><DT
300262685Sdelphij>1. <A
301262685SdelphijHREF="#INTRO"
302262685Sdelphij>Introduction</A
303262685Sdelphij></DT
304262685Sdelphij><DD
305262685Sdelphij><DL
306262685Sdelphij><DT
307262685Sdelphij>1.1. <A
308262685SdelphijHREF="#WHATIS"
309262685Sdelphij>What is NCURSES?</A
310262685Sdelphij></DT
311262685Sdelphij><DT
312262685Sdelphij>1.2. <A
313262685SdelphijHREF="#WHATCANWEDO"
314262685Sdelphij>What we can do with NCURSES</A
315262685Sdelphij></DT
316262685Sdelphij><DT
317262685Sdelphij>1.3. <A
318262685SdelphijHREF="#WHERETOGETIT"
319262685Sdelphij>Where to get it</A
320262685Sdelphij></DT
321262685Sdelphij><DT
322262685Sdelphij>1.4. <A
323262685SdelphijHREF="#PURPOSE"
324262685Sdelphij>Purpose/Scope of the document</A
325262685Sdelphij></DT
326262685Sdelphij><DT
327262685Sdelphij>1.5. <A
328262685SdelphijHREF="#ABOUTPROGRAMS"
329262685Sdelphij>About the Programs</A
330262685Sdelphij></DT
331262685Sdelphij><DT
332262685Sdelphij>1.6. <A
333262685SdelphijHREF="#OTHERFORMATS"
334262685Sdelphij>Other Formats of the document</A
335262685Sdelphij></DT
336262685Sdelphij><DD
337262685Sdelphij><DL
338262685Sdelphij><DT
339262685Sdelphij>1.6.1. <A
340262685SdelphijHREF="#LISTFORMATS"
341262685Sdelphij>Readily available formats from tldp.org</A
342262685Sdelphij></DT
343262685Sdelphij><DT
344262685Sdelphij>1.6.2. <A
345262685SdelphijHREF="#BUILDSOURCE"
346262685Sdelphij>Building from source</A
347262685Sdelphij></DT
348262685Sdelphij></DL
349262685Sdelphij></DD
350262685Sdelphij><DT
351262685Sdelphij>1.7. <A
352262685SdelphijHREF="#CREDITS"
353262685Sdelphij>Credits</A
354262685Sdelphij></DT
355262685Sdelphij><DT
356262685Sdelphij>1.8. <A
357262685SdelphijHREF="#WISHLIST"
358262685Sdelphij>Wish List</A
359262685Sdelphij></DT
360262685Sdelphij><DT
361262685Sdelphij>1.9. <A
362262685SdelphijHREF="#COPYRIGHT"
363262685Sdelphij>Copyright</A
364262685Sdelphij></DT
365262685Sdelphij></DL
366262685Sdelphij></DD
367262685Sdelphij><DT
368262685Sdelphij>2. <A
369262685SdelphijHREF="#HELLOWORLD"
370262685Sdelphij>Hello World !!!</A
371262685Sdelphij></DT
372262685Sdelphij><DD
373262685Sdelphij><DL
374262685Sdelphij><DT
375262685Sdelphij>2.1. <A
376262685SdelphijHREF="#COMPILECURSES"
377262685Sdelphij>Compiling With the NCURSES Library</A
378262685Sdelphij></DT
379262685Sdelphij><DT
380262685Sdelphij>2.2. <A
381262685SdelphijHREF="#DISSECTION"
382262685Sdelphij>Dissection</A
383262685Sdelphij></DT
384262685Sdelphij><DD
385262685Sdelphij><DL
386262685Sdelphij><DT
387262685Sdelphij>2.2.1. <A
388262685SdelphijHREF="#ABOUT-INITSCR"
389262685Sdelphij>About initscr()</A
390262685Sdelphij></DT
391262685Sdelphij><DT
392262685Sdelphij>2.2.2. <A
393262685SdelphijHREF="#MYST-REFRESH"
394262685Sdelphij>The mysterious refresh()</A
395262685Sdelphij></DT
396262685Sdelphij><DT
397262685Sdelphij>2.2.3. <A
398262685SdelphijHREF="#ABOUT-ENDWIN"
399262685Sdelphij>About endwin()</A
400262685Sdelphij></DT
401262685Sdelphij></DL
402262685Sdelphij></DD
403262685Sdelphij></DL
404262685Sdelphij></DD
405262685Sdelphij><DT
406262685Sdelphij>3. <A
407262685SdelphijHREF="#GORY"
408262685Sdelphij>The Gory Details</A
409262685Sdelphij></DT
410262685Sdelphij><DT
411262685Sdelphij>4. <A
412262685SdelphijHREF="#INIT"
413262685Sdelphij>Initialization</A
414262685Sdelphij></DT
415262685Sdelphij><DD
416262685Sdelphij><DL
417262685Sdelphij><DT
418262685Sdelphij>4.1. <A
419262685SdelphijHREF="#ABOUTINIT"
420262685Sdelphij>Initialization functions</A
421262685Sdelphij></DT
422262685Sdelphij><DT
423262685Sdelphij>4.2. <A
424262685SdelphijHREF="#RAWCBREAK"
425262685Sdelphij>raw() and cbreak()</A
426262685Sdelphij></DT
427262685Sdelphij><DT
428262685Sdelphij>4.3. <A
429262685SdelphijHREF="#ECHONOECHO"
430262685Sdelphij>echo() and noecho()</A
431262685Sdelphij></DT
432262685Sdelphij><DT
433262685Sdelphij>4.4. <A
434262685SdelphijHREF="#KEYPAD"
435262685Sdelphij>keypad()</A
436262685Sdelphij></DT
437262685Sdelphij><DT
438262685Sdelphij>4.5. <A
439262685SdelphijHREF="#HALFDELAY"
440262685Sdelphij>halfdelay()</A
441262685Sdelphij></DT
442262685Sdelphij><DT
443262685Sdelphij>4.6. <A
444262685SdelphijHREF="#MISCINIT"
445262685Sdelphij>Miscellaneous Initialization functions</A
446262685Sdelphij></DT
447262685Sdelphij><DT
448262685Sdelphij>4.7. <A
449262685SdelphijHREF="#INITEX"
450262685Sdelphij>An Example</A
451262685Sdelphij></DT
452262685Sdelphij></DL
453262685Sdelphij></DD
454262685Sdelphij><DT
455262685Sdelphij>5. <A
456262685SdelphijHREF="#AWORDWINDOWS"
457262685Sdelphij>A Word about Windows</A
458262685Sdelphij></DT
459262685Sdelphij><DT
460262685Sdelphij>6. <A
461262685SdelphijHREF="#PRINTW"
462262685Sdelphij>Output functions</A
463262685Sdelphij></DT
464262685Sdelphij><DD
465262685Sdelphij><DL
466262685Sdelphij><DT
467262685Sdelphij>6.1. <A
468262685SdelphijHREF="#ADDCHCLASS"
469262685Sdelphij>addch() class of functions</A
470262685Sdelphij></DT
471262685Sdelphij><DT
472262685Sdelphij>6.2. <A
473262685SdelphijHREF="#AEN298"
474262685Sdelphij>mvaddch(), waddch() and mvwaddch()</A
475262685Sdelphij></DT
476262685Sdelphij><DT
477262685Sdelphij>6.3. <A
478262685SdelphijHREF="#PRINTWCLASS"
479262685Sdelphij>printw() class of functions</A
480262685Sdelphij></DT
481262685Sdelphij><DD
482262685Sdelphij><DL
483262685Sdelphij><DT
484262685Sdelphij>6.3.1. <A
485262685SdelphijHREF="#PRINTWMVPRINTW"
486262685Sdelphij>printw() and mvprintw</A
487262685Sdelphij></DT
488262685Sdelphij><DT
489262685Sdelphij>6.3.2. <A
490262685SdelphijHREF="#WPRINTWMVWPRINTW"
491262685Sdelphij>wprintw() and mvwprintw</A
492262685Sdelphij></DT
493262685Sdelphij><DT
494262685Sdelphij>6.3.3. <A
495262685SdelphijHREF="#VWPRINTW"
496262685Sdelphij>vwprintw()</A
497262685Sdelphij></DT
498262685Sdelphij><DT
499262685Sdelphij>6.3.4. <A
500262685SdelphijHREF="#SIMPLEPRINTWEX"
501262685Sdelphij>A Simple printw example</A
502262685Sdelphij></DT
503262685Sdelphij></DL
504262685Sdelphij></DD
505262685Sdelphij><DT
506262685Sdelphij>6.4. <A
507262685SdelphijHREF="#ADDSTRCLASS"
508262685Sdelphij>addstr() class of functions</A
509262685Sdelphij></DT
510262685Sdelphij><DT
511262685Sdelphij>6.5. <A
512262685SdelphijHREF="#ACAUTION"
513262685Sdelphij>A word of caution</A
514262685Sdelphij></DT
515262685Sdelphij></DL
516262685Sdelphij></DD
517262685Sdelphij><DT
518262685Sdelphij>7. <A
519262685SdelphijHREF="#SCANW"
520262685Sdelphij>Input functions</A
521262685Sdelphij></DT
522262685Sdelphij><DD
523262685Sdelphij><DL
524262685Sdelphij><DT
525262685Sdelphij>7.1. <A
526262685SdelphijHREF="#GETCHCLASS"
527262685Sdelphij>getch() class of functions</A
528262685Sdelphij></DT
529262685Sdelphij><DT
530262685Sdelphij>7.2. <A
531262685SdelphijHREF="#SCANWCLASS"
532262685Sdelphij>scanw() class of functions</A
533262685Sdelphij></DT
534262685Sdelphij><DD
535262685Sdelphij><DL
536262685Sdelphij><DT
537262685Sdelphij>7.2.1. <A
538262685SdelphijHREF="#SCANWMVSCANW"
539262685Sdelphij>scanw() and mvscanw</A
540262685Sdelphij></DT
541262685Sdelphij><DT
542262685Sdelphij>7.2.2. <A
543262685SdelphijHREF="#WSCANWMVWSCANW"
544262685Sdelphij>wscanw() and mvwscanw()</A
545262685Sdelphij></DT
546262685Sdelphij><DT
547262685Sdelphij>7.2.3. <A
548262685SdelphijHREF="#VWSCANW"
549262685Sdelphij>vwscanw()</A
550262685Sdelphij></DT
551262685Sdelphij></DL
552262685Sdelphij></DD
553262685Sdelphij><DT
554262685Sdelphij>7.3. <A
555262685SdelphijHREF="#GETSTRCLASS"
556262685Sdelphij>getstr() class of functions</A
557262685Sdelphij></DT
558262685Sdelphij><DT
559262685Sdelphij>7.4. <A
560262685SdelphijHREF="#GETSTREX"
561262685Sdelphij>Some examples</A
562262685Sdelphij></DT
563262685Sdelphij></DL
564262685Sdelphij></DD
565262685Sdelphij><DT
566262685Sdelphij>8. <A
567262685SdelphijHREF="#ATTRIB"
568262685Sdelphij>Attributes</A
569262685Sdelphij></DT
570262685Sdelphij><DD
571262685Sdelphij><DL
572262685Sdelphij><DT
573262685Sdelphij>8.1. <A
574262685SdelphijHREF="#ATTRIBDETAILS"
575262685Sdelphij>The details</A
576262685Sdelphij></DT
577262685Sdelphij><DT
578262685Sdelphij>8.2. <A
579262685SdelphijHREF="#ATTRONVSATTRSET"
580262685Sdelphij>attron() vs attrset()</A
581262685Sdelphij></DT
582262685Sdelphij><DT
583262685Sdelphij>8.3. <A
584262685SdelphijHREF="#ATTR_GET"
585262685Sdelphij>attr_get()</A
586262685Sdelphij></DT
587262685Sdelphij><DT
588262685Sdelphij>8.4. <A
589262685SdelphijHREF="#ATTR_FUNCS"
590262685Sdelphij>attr_ functions</A
591262685Sdelphij></DT
592262685Sdelphij><DT
593262685Sdelphij>8.5. <A
594262685SdelphijHREF="#WATTRFUNCS"
595262685Sdelphij>wattr functions</A
596262685Sdelphij></DT
597262685Sdelphij><DT
598262685Sdelphij>8.6. <A
599262685SdelphijHREF="#CHGAT"
600262685Sdelphij>chgat() functions</A
601262685Sdelphij></DT
602262685Sdelphij></DL
603262685Sdelphij></DD
604262685Sdelphij><DT
605262685Sdelphij>9. <A
606262685SdelphijHREF="#WINDOWS"
607262685Sdelphij>Windows</A
608262685Sdelphij></DT
609262685Sdelphij><DD
610262685Sdelphij><DL
611262685Sdelphij><DT
612262685Sdelphij>9.1. <A
613262685SdelphijHREF="#WINDOWBASICS"
614262685Sdelphij>The basics</A
615262685Sdelphij></DT
616262685Sdelphij><DT
617262685Sdelphij>9.2. <A
618262685SdelphijHREF="#LETBEWINDOW"
619262685Sdelphij>Let there be a Window !!!</A
620262685Sdelphij></DT
621262685Sdelphij><DT
622262685Sdelphij>9.3. <A
623262685SdelphijHREF="#BORDEREXEXPL"
624262685Sdelphij>Explanation</A
625262685Sdelphij></DT
626262685Sdelphij><DT
627262685Sdelphij>9.4. <A
628262685SdelphijHREF="#OTHERSTUFF"
629262685Sdelphij>The other stuff in the example</A
630262685Sdelphij></DT
631262685Sdelphij><DT
632262685Sdelphij>9.5. <A
633262685SdelphijHREF="#OTHERBORDERFUNCS"
634262685Sdelphij>Other Border functions</A
635262685Sdelphij></DT
636262685Sdelphij></DL
637262685Sdelphij></DD
638262685Sdelphij><DT
639262685Sdelphij>10. <A
640262685SdelphijHREF="#COLOR"
641262685Sdelphij>Colors</A
642262685Sdelphij></DT
643262685Sdelphij><DD
644262685Sdelphij><DL
645262685Sdelphij><DT
646262685Sdelphij>10.1. <A
647262685SdelphijHREF="#COLORBASICS"
648262685Sdelphij>The basics</A
649262685Sdelphij></DT
650262685Sdelphij><DT
651262685Sdelphij>10.2. <A
652262685SdelphijHREF="#CHANGECOLORDEFS"
653262685Sdelphij>Changing Color Definitions</A
654262685Sdelphij></DT
655262685Sdelphij><DT
656262685Sdelphij>10.3. <A
657262685SdelphijHREF="#COLORCONTENT"
658262685Sdelphij>Color Content</A
659262685Sdelphij></DT
660262685Sdelphij></DL
661262685Sdelphij></DD
662262685Sdelphij><DT
663262685Sdelphij>11. <A
664262685SdelphijHREF="#KEYS"
665262685Sdelphij>Interfacing with the key board</A
666262685Sdelphij></DT
667262685Sdelphij><DD
668262685Sdelphij><DL
669262685Sdelphij><DT
670262685Sdelphij>11.1. <A
671262685SdelphijHREF="#KEYSBASICS"
672262685Sdelphij>The Basics</A
673262685Sdelphij></DT
674262685Sdelphij><DT
675262685Sdelphij>11.2. <A
676262685SdelphijHREF="#SIMPLEKEYEX"
677262685Sdelphij>A Simple Key Usage example</A
678262685Sdelphij></DT
679262685Sdelphij></DL
680262685Sdelphij></DD
681262685Sdelphij><DT
682262685Sdelphij>12. <A
683262685SdelphijHREF="#MOUSE"
684262685Sdelphij>Interfacing with the mouse</A
685262685Sdelphij></DT
686262685Sdelphij><DD
687262685Sdelphij><DL
688262685Sdelphij><DT
689262685Sdelphij>12.1. <A
690262685SdelphijHREF="#MOUSEBASICS"
691262685Sdelphij>The Basics</A
692262685Sdelphij></DT
693262685Sdelphij><DT
694262685Sdelphij>12.2. <A
695262685SdelphijHREF="#GETTINGEVENTS"
696262685Sdelphij>Getting the events</A
697262685Sdelphij></DT
698262685Sdelphij><DT
699262685Sdelphij>12.3. <A
700262685SdelphijHREF="#MOUSETOGETHER"
701262685Sdelphij>Putting it all Together</A
702262685Sdelphij></DT
703262685Sdelphij><DT
704262685Sdelphij>12.4. <A
705262685SdelphijHREF="#MISCMOUSEFUNCS"
706262685Sdelphij>Miscellaneous Functions</A
707262685Sdelphij></DT
708262685Sdelphij></DL
709262685Sdelphij></DD
710262685Sdelphij><DT
711262685Sdelphij>13. <A
712262685SdelphijHREF="#SCREEN"
713262685Sdelphij>Screen Manipulation</A
714262685Sdelphij></DT
715262685Sdelphij><DD
716262685Sdelphij><DL
717262685Sdelphij><DT
718262685Sdelphij>13.1. <A
719262685SdelphijHREF="#GETYX"
720262685Sdelphij>getyx() functions</A
721262685Sdelphij></DT
722262685Sdelphij><DT
723262685Sdelphij>13.2. <A
724262685SdelphijHREF="#SCREENDUMP"
725262685Sdelphij>Screen Dumping</A
726262685Sdelphij></DT
727262685Sdelphij><DT
728262685Sdelphij>13.3. <A
729262685SdelphijHREF="#WINDOWDUMP"
730262685Sdelphij>Window Dumping</A
731262685Sdelphij></DT
732262685Sdelphij></DL
733262685Sdelphij></DD
734262685Sdelphij><DT
735262685Sdelphij>14. <A
736262685SdelphijHREF="#MISC"
737262685Sdelphij>Miscellaneous features</A
738262685Sdelphij></DT
739262685Sdelphij><DD
740262685Sdelphij><DL
741262685Sdelphij><DT
742262685Sdelphij>14.1. <A
743262685SdelphijHREF="#CURSSET"
744262685Sdelphij>curs_set()</A
745262685Sdelphij></DT
746262685Sdelphij><DT
747262685Sdelphij>14.2. <A
748262685SdelphijHREF="#TEMPLEAVE"
749262685Sdelphij>Temporarily Leaving Curses mode</A
750262685Sdelphij></DT
751262685Sdelphij><DT
752262685Sdelphij>14.3. <A
753262685SdelphijHREF="#ACSVARS"
754262685Sdelphij>ACS_ variables</A
755262685Sdelphij></DT
756262685Sdelphij></DL
757262685Sdelphij></DD
758262685Sdelphij><DT
759262685Sdelphij>15. <A
760262685SdelphijHREF="#OTHERLIB"
761262685Sdelphij>Other libraries</A
762262685Sdelphij></DT
763262685Sdelphij><DT
764262685Sdelphij>16. <A
765262685SdelphijHREF="#PANELS"
766262685Sdelphij>Panel Library</A
767262685Sdelphij></DT
768262685Sdelphij><DD
769262685Sdelphij><DL
770262685Sdelphij><DT
771262685Sdelphij>16.1. <A
772262685SdelphijHREF="#PANELBASICS"
773262685Sdelphij>The Basics</A
774262685Sdelphij></DT
775262685Sdelphij><DT
776262685Sdelphij>16.2. <A
777262685SdelphijHREF="#COMPILEPANELS"
778262685Sdelphij>Compiling With the Panels Library</A
779262685Sdelphij></DT
780262685Sdelphij><DT
781262685Sdelphij>16.3. <A
782262685SdelphijHREF="#PANELBROWSING"
783262685Sdelphij>Panel Window Browsing</A
784262685Sdelphij></DT
785262685Sdelphij><DT
786262685Sdelphij>16.4. <A
787262685SdelphijHREF="#USERPTRUSING"
788262685Sdelphij>Using User Pointers</A
789262685Sdelphij></DT
790262685Sdelphij><DT
791262685Sdelphij>16.5. <A
792262685SdelphijHREF="#PANELMOVERESIZE"
793262685Sdelphij>Moving and Resizing Panels</A
794262685Sdelphij></DT
795262685Sdelphij><DT
796262685Sdelphij>16.6. <A
797262685SdelphijHREF="#PANELSHOWHIDE"
798262685Sdelphij>Hiding and Showing Panels</A
799262685Sdelphij></DT
800262685Sdelphij><DT
801262685Sdelphij>16.7. <A
802262685SdelphijHREF="#PANELABOVE"
803262685Sdelphij>panel_above() and panel_below() Functions</A
804262685Sdelphij></DT
805262685Sdelphij></DL
806262685Sdelphij></DD
807262685Sdelphij><DT
808262685Sdelphij>17. <A
809262685SdelphijHREF="#MENUS"
810262685Sdelphij>Menus Library</A
811262685Sdelphij></DT
812262685Sdelphij><DD
813262685Sdelphij><DL
814262685Sdelphij><DT
815262685Sdelphij>17.1. <A
816262685SdelphijHREF="#MENUBASICS"
817262685Sdelphij>The Basics</A
818262685Sdelphij></DT
819262685Sdelphij><DT
820262685Sdelphij>17.2. <A
821262685SdelphijHREF="#COMPILEMENUS"
822262685Sdelphij>Compiling With the Menu Library</A
823262685Sdelphij></DT
824262685Sdelphij><DT
825262685Sdelphij>17.3. <A
826262685SdelphijHREF="#MENUDRIVER"
827262685Sdelphij>Menu Driver: The work horse of the menu system</A
828262685Sdelphij></DT
829262685Sdelphij><DT
830262685Sdelphij>17.4. <A
831262685SdelphijHREF="#MENUWINDOWS"
832262685Sdelphij>Menu Windows</A
833262685Sdelphij></DT
834262685Sdelphij><DT
835262685Sdelphij>17.5. <A
836262685SdelphijHREF="#SCROLLMENUS"
837262685Sdelphij>Scrolling Menus</A
838262685Sdelphij></DT
839262685Sdelphij><DT
840262685Sdelphij>17.6. <A
841262685SdelphijHREF="#MULTICOLUMN"
842262685Sdelphij>Multi Columnar Menus</A
843262685Sdelphij></DT
844262685Sdelphij><DT
845262685Sdelphij>17.7. <A
846262685SdelphijHREF="#MULTIVALUEMENUS"
847262685Sdelphij>Multi Valued Menus</A
848262685Sdelphij></DT
849262685Sdelphij><DT
850262685Sdelphij>17.8. <A
851262685SdelphijHREF="#MENUOPT"
852262685Sdelphij>Menu Options</A
853262685Sdelphij></DT
854262685Sdelphij><DT
855262685Sdelphij>17.9. <A
856262685SdelphijHREF="#MENUUSERPTR"
857262685Sdelphij>The useful User Pointer</A
858262685Sdelphij></DT
859262685Sdelphij></DL
860262685Sdelphij></DD
861262685Sdelphij><DT
862262685Sdelphij>18. <A
863262685SdelphijHREF="#FORMS"
864262685Sdelphij>Forms Library</A
865262685Sdelphij></DT
866262685Sdelphij><DD
867262685Sdelphij><DL
868262685Sdelphij><DT
869262685Sdelphij>18.1. <A
870262685SdelphijHREF="#FORMBASICS"
871262685Sdelphij>The Basics</A
872262685Sdelphij></DT
873262685Sdelphij><DT
874262685Sdelphij>18.2. <A
875262685SdelphijHREF="#COMPILEFORMS"
876262685Sdelphij>Compiling With the Forms Library</A
877262685Sdelphij></DT
878262685Sdelphij><DT
879262685Sdelphij>18.3. <A
880262685SdelphijHREF="#PLAYFIELDS"
881262685Sdelphij>Playing with Fields</A
882262685Sdelphij></DT
883262685Sdelphij><DD
884262685Sdelphij><DL
885262685Sdelphij><DT
886262685Sdelphij>18.3.1. <A
887262685SdelphijHREF="#FETCHINFO"
888262685Sdelphij>Fetching Size and Location of Field</A
889262685Sdelphij></DT
890262685Sdelphij><DT
891262685Sdelphij>18.3.2. <A
892262685SdelphijHREF="#MOVEFIELD"
893262685Sdelphij>Moving the field</A
894262685Sdelphij></DT
895262685Sdelphij><DT
896262685Sdelphij>18.3.3. <A
897262685SdelphijHREF="#JUSTIFYFIELD"
898262685Sdelphij>Field Justification</A
899262685Sdelphij></DT
900262685Sdelphij><DT
901262685Sdelphij>18.3.4. <A
902262685SdelphijHREF="#FIELDDISPATTRIB"
903262685Sdelphij>Field Display Attributes</A
904262685Sdelphij></DT
905262685Sdelphij><DT
906262685Sdelphij>18.3.5. <A
907262685SdelphijHREF="#FIELDOPTIONBITS"
908262685Sdelphij>Field Option Bits</A
909262685Sdelphij></DT
910262685Sdelphij><DT
911262685Sdelphij>18.3.6. <A
912262685SdelphijHREF="#FIELDSTATUS"
913262685Sdelphij>Field Status</A
914262685Sdelphij></DT
915262685Sdelphij><DT
916262685Sdelphij>18.3.7. <A
917262685SdelphijHREF="#FIELDUSERPTR"
918262685Sdelphij>Field User Pointer</A
919262685Sdelphij></DT
920262685Sdelphij><DT
921262685Sdelphij>18.3.8. <A
922262685SdelphijHREF="#VARIABLESIZEFIELDS"
923262685Sdelphij>Variable-Sized Fields</A
924262685Sdelphij></DT
925262685Sdelphij></DL
926262685Sdelphij></DD
927262685Sdelphij><DT
928262685Sdelphij>18.4. <A
929262685SdelphijHREF="#FORMWINDOWS"
930262685Sdelphij>Form Windows</A
931262685Sdelphij></DT
932262685Sdelphij><DT
933262685Sdelphij>18.5. <A
934262685SdelphijHREF="#FILEDVALIDATE"
935262685Sdelphij>Field Validation</A
936262685Sdelphij></DT
937262685Sdelphij><DT
938262685Sdelphij>18.6. <A
939262685SdelphijHREF="#FORMDRIVER"
940262685Sdelphij>Form Driver: The work horse of the forms system</A
941262685Sdelphij></DT
942262685Sdelphij><DD
943262685Sdelphij><DL
944262685Sdelphij><DT
945262685Sdelphij>18.6.1. <A
946262685SdelphijHREF="#PAGENAVREQ"
947262685Sdelphij>Page Navigation Requests</A
948262685Sdelphij></DT
949262685Sdelphij><DT
950262685Sdelphij>18.6.2. <A
951262685SdelphijHREF="#INTERFIELDNAVREQ"
952262685Sdelphij>Inter-Field Navigation Requests</A
953262685Sdelphij></DT
954262685Sdelphij><DT
955262685Sdelphij>18.6.3. <A
956262685SdelphijHREF="#INTRAFIELDNAVREQ"
957262685Sdelphij>Intra-Field Navigation Requests</A
958262685Sdelphij></DT
959262685Sdelphij><DT
960262685Sdelphij>18.6.4. <A
961262685SdelphijHREF="#SCROLLREQ"
962262685Sdelphij>Scrolling Requests</A
963262685Sdelphij></DT
964262685Sdelphij><DT
965262685Sdelphij>18.6.5. <A
966262685SdelphijHREF="#EDITREQ"
967262685Sdelphij>Editing Requests</A
968262685Sdelphij></DT
969262685Sdelphij><DT
970262685Sdelphij>18.6.6. <A
971262685SdelphijHREF="#ORDERREQ"
972262685Sdelphij>Order Requests</A
973262685Sdelphij></DT
974262685Sdelphij><DT
975262685Sdelphij>18.6.7. <A
976262685SdelphijHREF="#APPLICCOMMANDS"
977262685Sdelphij>Application Commands</A
978262685Sdelphij></DT
979262685Sdelphij></DL
980262685Sdelphij></DD
981262685Sdelphij></DL
982262685Sdelphij></DD
983262685Sdelphij><DT
984262685Sdelphij>19. <A
985262685SdelphijHREF="#TOOLS"
986262685Sdelphij>Tools and Widget Libraries</A
987262685Sdelphij></DT
988262685Sdelphij><DD
989262685Sdelphij><DL
990262685Sdelphij><DT
991262685Sdelphij>19.1. <A
992262685SdelphijHREF="#CDK"
993262685Sdelphij>CDK (Curses Development Kit)</A
994262685Sdelphij></DT
995262685Sdelphij><DD
996262685Sdelphij><DL
997262685Sdelphij><DT
998262685Sdelphij>19.1.1. <A
999262685SdelphijHREF="#WIDGETLIST"
1000262685Sdelphij>Widget List</A
1001262685Sdelphij></DT
1002262685Sdelphij><DT
1003262685Sdelphij>19.1.2. <A
1004262685SdelphijHREF="#CDKATTRACT"
1005262685Sdelphij>Some Attractive Features</A
1006262685Sdelphij></DT
1007262685Sdelphij><DT
1008262685Sdelphij>19.1.3. <A
1009262685SdelphijHREF="#CDKCONCLUSION"
1010262685Sdelphij>Conclusion</A
1011262685Sdelphij></DT
1012262685Sdelphij></DL
1013262685Sdelphij></DD
1014262685Sdelphij><DT
1015262685Sdelphij>19.2. <A
1016262685SdelphijHREF="#DIALOG"
1017262685Sdelphij>The dialog</A
1018262685Sdelphij></DT
1019262685Sdelphij><DT
1020262685Sdelphij>19.3. <A
1021262685SdelphijHREF="#PERLCURSES"
1022262685Sdelphij>Perl Curses Modules CURSES::FORM and CURSES::WIDGETS</A
1023262685Sdelphij></DT
1024262685Sdelphij></DL
1025262685Sdelphij></DD
1026262685Sdelphij><DT
1027262685Sdelphij>20. <A
1028262685SdelphijHREF="#JUSTFORFUN"
1029262685Sdelphij>Just For Fun !!!</A
1030262685Sdelphij></DT
1031262685Sdelphij><DD
1032262685Sdelphij><DL
1033262685Sdelphij><DT
1034262685Sdelphij>20.1. <A
1035262685SdelphijHREF="#GAMEOFLIFE"
1036262685Sdelphij>The Game of Life</A
1037262685Sdelphij></DT
1038262685Sdelphij><DT
1039262685Sdelphij>20.2. <A
1040262685SdelphijHREF="#MAGIC"
1041262685Sdelphij>Magic Square</A
1042262685Sdelphij></DT
1043262685Sdelphij><DT
1044262685Sdelphij>20.3. <A
1045262685SdelphijHREF="#HANOI"
1046262685Sdelphij>Towers of Hanoi</A
1047262685Sdelphij></DT
1048262685Sdelphij><DT
1049262685Sdelphij>20.4. <A
1050262685SdelphijHREF="#QUEENS"
1051262685Sdelphij>Queens Puzzle</A
1052262685Sdelphij></DT
1053262685Sdelphij><DT
1054262685Sdelphij>20.5. <A
1055262685SdelphijHREF="#SHUFFLE"
1056262685Sdelphij>Shuffle</A
1057262685Sdelphij></DT
1058262685Sdelphij><DT
1059262685Sdelphij>20.6. <A
1060262685SdelphijHREF="#TT"
1061262685Sdelphij>Typing Tutor</A
1062262685Sdelphij></DT
1063262685Sdelphij></DL
1064262685Sdelphij></DD
1065262685Sdelphij><DT
1066262685Sdelphij>21. <A
1067262685SdelphijHREF="#REF"
1068262685Sdelphij>References</A
1069262685Sdelphij></DT
1070262685Sdelphij></DL
1071262685Sdelphij></DIV
1072262685Sdelphij><DIV
1073262685SdelphijCLASS="SECT1"
1074262685Sdelphij><H2
1075262685SdelphijCLASS="SECT1"
1076262685Sdelphij><A
1077262685SdelphijNAME="INTRO"
1078262685Sdelphij>1. Introduction</A
1079262685Sdelphij></H2
1080262685Sdelphij><P
1081262685Sdelphij>In the olden days of teletype terminals, terminals were away from computers and
1082262685Sdelphijwere connected to them through serial cables. The terminals could be configured
1083262685Sdelphijby sending a series of bytes. All the capabilities (such as 
1084262685Sdelphijmoving the cursor to a new location, erasing part of the screen, scrolling the 
1085262685Sdelphijscreen, changing modes etc.) of terminals could be accessed through these 
1086262685Sdelphijseries of bytes. These control seeuqnces are usually called escape sequences, 
1087262685Sdelphijbecause they start 
1088262685Sdelphijwith an escape(0x1B) character. Even today, with proper emulation, we can send 
1089262685Sdelphijescape sequences to the emulator and achieve the same effect on a terminal 
1090262685Sdelphijwindow.</P
1091262685Sdelphij><P
1092262685Sdelphij>Suppose you wanted to print a line in color. Try typing this on your console.</P
1093262685Sdelphij><PRE
1094262685SdelphijCLASS="PROGRAMLISTING"
1095262685Sdelphij>echo "^[[0;31;40mIn Color"</PRE
1096262685Sdelphij><P
1097262685Sdelphij>The first character is an escape character, which looks like two characters ^ 
1098262685Sdelphijand [. To be able to print it, you have to press CTRL+V and then the ESC key. 
1099262685SdelphijAll the others are normal printable characters. You should be able to see the 
1100262685Sdelphijstring "In Color" in red. It stays that way and to revert back to the original 
1101262685Sdelphijmode type this.</P
1102262685Sdelphij><PRE
1103262685SdelphijCLASS="PROGRAMLISTING"
1104262685Sdelphij>echo "^[[0;37;40m"</PRE
1105262685Sdelphij><P
1106262685Sdelphij>Now, what do these magic characters mean? Difficult to comprehend? They might
1107262685Sdelphijeven be different for different terminals. So the designers of UNIX invented a 
1108262685Sdelphijmechanism named <TT
1109262685SdelphijCLASS="LITERAL"
1110262685Sdelphij>termcap</TT
1111262685Sdelphij>. It is a file that
1112262685Sdelphijlists all the capabilities of a particular terminal, along with the escape
1113262685Sdelphijsequences needed to achieve a particular effect. In the later years, this was 
1114262685Sdelphijreplaced by <TT
1115262685SdelphijCLASS="LITERAL"
1116262685Sdelphij>terminfo</TT
1117262685Sdelphij>. Without delving too 
1118262685Sdelphijmuch into details, this mechanism allows application 
1119262685Sdelphijprograms to query the terminfo database and obtain the control characters to be 
1120262685Sdelphijsent to a terminal or terminal emulator.</P
1121262685Sdelphij><DIV
1122262685SdelphijCLASS="SECT2"
1123262685Sdelphij><HR><H3
1124262685SdelphijCLASS="SECT2"
1125262685Sdelphij><A
1126262685SdelphijNAME="WHATIS"
1127262685Sdelphij>1.1. What is NCURSES?</A
1128262685Sdelphij></H3
1129262685Sdelphij><P
1130262685Sdelphij> 
1131262685SdelphijYou might be wondering, what the import of all this technical gibberish is.  In
1132262685Sdelphijthe above scenario, every application program is supposed to query the terminfo
1133262685Sdelphijand perform the necessary stuff (sending control characters etc.).  It soon became
1134262685Sdelphijdifficult to manage this complexity and this gave birth to 'CURSES'.  Curses is
1135262685Sdelphija pun on the name "cursor optimization". The Curses library forms a wrapper
1136262685Sdelphijover working with raw terminal codes, and provides highly flexible and
1137262685Sdelphijefficient API (Application Programming Interface). It provides functions to
1138262685Sdelphijmove the cursor, create windows, produce colors, play with mouse etc.  The
1139262685Sdelphijapplication programs need not worry about the underlying terminal capabilities.</P
1140262685Sdelphij><P
1141262685Sdelphij>So what is NCURSES? NCURSES is a clone of the original System V Release 4.0
1142262685Sdelphij(SVr4) curses. It is a freely distributable library, fully compatible with
1143262685Sdelphijolder version of curses.  In short, it is a library of functions that manages
1144262685Sdelphijan application's display on character-cell terminals.  In the remainder of the
1145262685Sdelphijdocument, the terms curses and ncurses are used interchangeably.  </P
1146262685Sdelphij><P
1147262685Sdelphij>A detailed history of NCURSES can be found in the NEWS file from the source
1148262685Sdelphijdistribution. The current package is maintained by 
1149262685Sdelphij<A
1150262685SdelphijHREF="mailto:dickey@his.com"
1151262685SdelphijTARGET="_top"
1152262685Sdelphij>Thomas Dickey</A
1153262685Sdelphij>.  
1154262685SdelphijYou can contact the maintainers at <A
1155262685SdelphijHREF="mailto:bug-ncurses@gnu.org"
1156262685SdelphijTARGET="_top"
1157262685Sdelphij>bug-ncurses@gnu.org</A
1158262685Sdelphij>.</P
1159262685Sdelphij></DIV
1160262685Sdelphij><DIV
1161262685SdelphijCLASS="SECT2"
1162262685Sdelphij><HR><H3
1163262685SdelphijCLASS="SECT2"
1164262685Sdelphij><A
1165262685SdelphijNAME="WHATCANWEDO"
1166262685Sdelphij>1.2. What we can do with NCURSES</A
1167262685Sdelphij></H3
1168262685Sdelphij><P
1169262685Sdelphij>NCURSES not only creates a wrapper over terminal capabilities, but also gives a
1170262685Sdelphijrobust framework to create nice looking UI (User Interface)s in text mode.  It
1171262685Sdelphijprovides functions to create windows etc.  Its sister libraries panel, menu and
1172262685Sdelphijform provide an extension to the basic curses library. These libraries usually
1173262685Sdelphijcome along with curses. One can create applications that contain multiple
1174262685Sdelphijwindows, menus, panels and forms. Windows can be managed independently, can
1175262685Sdelphijprovide 'scrollability' and even can be hidden.</P
1176262685Sdelphij><P
1177262685Sdelphij> 
1178262685SdelphijMenus provide the user with an easy command selection option.  Forms allow the
1179262685Sdelphijcreation of easy-to-use data entry and display windows.  Panels extend the
1180262685Sdelphijcapabilities of ncurses to deal with overlapping and stacked windows.</P
1181262685Sdelphij><P
1182262685Sdelphij>These are just some of the basic things we can do with ncurses. As we move
1183262685Sdelphijalong, We will see all the capabilities of these libraries. </P
1184262685Sdelphij></DIV
1185262685Sdelphij><DIV
1186262685SdelphijCLASS="SECT2"
1187262685Sdelphij><HR><H3
1188262685SdelphijCLASS="SECT2"
1189262685Sdelphij><A
1190262685SdelphijNAME="WHERETOGETIT"
1191262685Sdelphij>1.3. Where to get it</A
1192262685Sdelphij></H3
1193262685Sdelphij><P
1194262685Sdelphij>All right, now that you know what you can do with ncurses, you must be rearing
1195262685Sdelphijto get started. NCURSES is usually shipped with your installation. In case
1196262685Sdelphijyou don't have the library or want to compile it on your own, read on.</P
1197262685Sdelphij><P
1198262685Sdelphij><SPAN
1199262685SdelphijCLASS="emphasis"
1200262685Sdelphij><I
1201262685SdelphijCLASS="EMPHASIS"
1202262685Sdelphij>Compiling the package</I
1203262685Sdelphij></SPAN
1204262685Sdelphij> </P
1205262685Sdelphij><P
1206262685Sdelphij>NCURSES can be obtained from <A
1207262685SdelphijHREF="ftp://ftp.gnu.org/pub/gnu/ncurses/ncurses.tar.gz"
1208262685SdelphijTARGET="_top"
1209262685Sdelphij>ftp://ftp.gnu.org/pub/gnu/ncurses/ncurses.tar.gz</A
1210262685Sdelphij> or any of the ftp 
1211262685Sdelphijsites mentioned in <A
1212262685SdelphijHREF="http://www.gnu.org/order/ftp.html"
1213262685SdelphijTARGET="_top"
1214262685Sdelphij>http://www.gnu.org/order/ftp.html</A
1215262685Sdelphij>. </P
1216262685Sdelphij><P
1217262685Sdelphij>Read the README and INSTALL files for details on to how to install it. It 
1218262685Sdelphijusually involves the following operations.</P
1219262685Sdelphij><PRE
1220262685SdelphijCLASS="PROGRAMLISTING"
1221262685Sdelphij>    tar zxvf ncurses&lt;version&gt;.tar.gz  # unzip and untar the archive
1222166124Srafan    cd ncurses&lt;version&gt;               # cd to the directory
1223166124Srafan    ./configure                             # configure the build according to your 
1224166124Srafan                                            # environment
1225166124Srafan    make                                    # make it
1226166124Srafan    su root                                 # become root
1227262685Sdelphij    make install                            # install it</PRE
1228262685Sdelphij><P
1229262685Sdelphij><SPAN
1230262685SdelphijCLASS="emphasis"
1231262685Sdelphij><I
1232262685SdelphijCLASS="EMPHASIS"
1233262685Sdelphij>Using the RPM </I
1234262685Sdelphij></SPAN
1235262685Sdelphij></P
1236262685Sdelphij><P
1237262685Sdelphij>NCURSES RPM can be found and downloaded from <A
1238262685SdelphijHREF="http://rpmfind.net"
1239262685SdelphijTARGET="_top"
1240262685Sdelphij>http://rpmfind.net </A
1241262685Sdelphij>. The RPM can be installed with the following 
1242262685Sdelphijcommand after becoming root.</P
1243262685Sdelphij><PRE
1244262685SdelphijCLASS="PROGRAMLISTING"
1245262685Sdelphij>    rpm -i &lt;downloaded rpm&gt;</PRE
1246262685Sdelphij></DIV
1247262685Sdelphij><DIV
1248262685SdelphijCLASS="SECT2"
1249262685Sdelphij><HR><H3
1250262685SdelphijCLASS="SECT2"
1251262685Sdelphij><A
1252262685SdelphijNAME="PURPOSE"
1253262685Sdelphij>1.4. Purpose/Scope of the document</A
1254262685Sdelphij></H3
1255262685Sdelphij><P
1256262685Sdelphij>This document is intended to be a "All in One" guide for programming with
1257262685Sdelphijncurses and its sister libraries. We graduate from a simple "Hello World"
1258262685Sdelphijprogram to more complex form manipulation. No prior experience in ncurses is
1259262685Sdelphijassumed. The writing is informal, but a lot of detail is provided for
1260262685Sdelphijeach of the examples.</P
1261262685Sdelphij></DIV
1262262685Sdelphij><DIV
1263262685SdelphijCLASS="SECT2"
1264262685Sdelphij><HR><H3
1265262685SdelphijCLASS="SECT2"
1266262685Sdelphij><A
1267262685SdelphijNAME="ABOUTPROGRAMS"
1268262685Sdelphij>1.5. About the Programs</A
1269262685Sdelphij></H3
1270262685Sdelphij><P
1271262685Sdelphij>All the programs in the document are available in zipped form
1272262685Sdelphij<A
1273262685SdelphijHREF="http://www.tldp.org/HOWTO/NCURSES-Programming-HOWTO/ncurses_programs.tar.gz"
1274262685SdelphijTARGET="_top"
1275262685Sdelphij>here</A
1276262685Sdelphij>. Unzip and untar it. The directory structure looks like this.</P
1277262685Sdelphij><PRE
1278262685SdelphijCLASS="PROGRAMLISTING"
1279262685Sdelphij>ncurses
1280166124Srafan   |
1281166124Srafan   |----&gt; JustForFun     -- just for fun programs
1282166124Srafan   |----&gt; basics         -- basic programs
1283166124Srafan   |----&gt; demo           -- output files go into this directory after make
1284166124Srafan   |          |
1285166124Srafan   |          |----&gt; exe -- exe files of all example programs
1286166124Srafan   |----&gt; forms          -- programs related to form library
1287166124Srafan   |----&gt; menus          -- programs related to menus library
1288166124Srafan   |----&gt; panels         -- programs related to panels library
1289166124Srafan   |----&gt; perl           -- perl equivalents of the examples (contributed
1290166124Srafan   |                            by Anuradha Ratnaweera)
1291166124Srafan   |----&gt; Makefile       -- the top level Makefile
1292166124Srafan   |----&gt; README         -- the top level README file. contains instructions
1293262685Sdelphij   |----&gt; COPYING        -- copyright notice</PRE
1294262685Sdelphij><P
1295262685Sdelphij>The individual directories contain the following files.</P
1296262685Sdelphij><PRE
1297262685SdelphijCLASS="PROGRAMLISTING"
1298262685Sdelphij>Description of files in each directory
1299166124Srafan--------------------------------------
1300166124SrafanJustForFun
1301166124Srafan    |
1302166124Srafan    |----&gt; hanoi.c   -- The Towers of Hanoi Solver
1303166124Srafan    |----&gt; life.c    -- The Game of Life demo
1304166124Srafan    |----&gt; magic.c   -- An Odd Order Magic Square builder 
1305166124Srafan    |----&gt; queens.c  -- The famous N-Queens Solver
1306166124Srafan    |----&gt; shuffle.c -- A fun game, if you have time to kill
1307166124Srafan    |----&gt; tt.c      -- A very trivial typing tutor
1308166124Srafan
1309166124Srafan  basics
1310166124Srafan    |
1311166124Srafan    |----&gt; acs_vars.c            -- ACS_ variables example
1312166124Srafan    |----&gt; hello_world.c         -- Simple "Hello World" Program
1313166124Srafan    |----&gt; init_func_example.c   -- Initialization functions example
1314166124Srafan    |----&gt; key_code.c            -- Shows the scan code of the key pressed
1315166124Srafan    |----&gt; mouse_menu.c          -- A menu accessible by mouse
1316166124Srafan    |----&gt; other_border.c        -- Shows usage of other border functions apa
1317166124Srafan    |                               -- rt from box()
1318166124Srafan    |----&gt; printw_example.c      -- A very simple printw() example
1319166124Srafan    |----&gt; scanw_example.c       -- A very simple getstr() example
1320166124Srafan    |----&gt; simple_attr.c         -- A program that can print a c file with 
1321166124Srafan    |                               -- comments in attribute
1322166124Srafan    |----&gt; simple_color.c        -- A simple example demonstrating colors
1323166124Srafan    |----&gt; simple_key.c          -- A menu accessible with keyboard UP, DOWN 
1324166124Srafan    |                               -- arrows
1325166124Srafan    |----&gt; temp_leave.c          -- Demonstrates temporarily leaving curses mode
1326166124Srafan    |----&gt; win_border.c          -- Shows Creation of windows and borders
1327166124Srafan    |----&gt; with_chgat.c          -- chgat() usage example
1328166124Srafan
1329166124Srafan  forms 
1330166124Srafan    |
1331166124Srafan    |----&gt; form_attrib.c     -- Usage of field attributes
1332166124Srafan    |----&gt; form_options.c    -- Usage of field options
1333166124Srafan    |----&gt; form_simple.c     -- A simple form example
1334166124Srafan    |----&gt; form_win.c        -- Demo of windows associated with forms
1335166124Srafan
1336166124Srafan  menus 
1337166124Srafan    |
1338166124Srafan    |----&gt; menu_attrib.c     -- Usage of menu attributes
1339166124Srafan    |----&gt; menu_item_data.c  -- Usage of item_name() etc.. functions
1340166124Srafan    |----&gt; menu_multi_column.c    -- Creates multi columnar menus
1341166124Srafan    |----&gt; menu_scroll.c     -- Demonstrates scrolling capability of menus
1342166124Srafan    |----&gt; menu_simple.c     -- A simple menu accessed by arrow keys
1343166124Srafan    |----&gt; menu_toggle.c     -- Creates multi valued menus and explains
1344166124Srafan    |                           -- REQ_TOGGLE_ITEM
1345166124Srafan    |----&gt; menu_userptr.c    -- Usage of user pointer
1346166124Srafan    |----&gt; menu_win.c        -- Demo of windows associated with menus
1347166124Srafan
1348166124Srafan  panels 
1349166124Srafan    |
1350166124Srafan    |----&gt; panel_browse.c    -- Panel browsing through tab. Usage of user 
1351166124Srafan    |                           -- pointer
1352166124Srafan    |----&gt; panel_hide.c      -- Hiding and Un hiding of panels
1353166124Srafan    |----&gt; panel_resize.c    -- Moving and resizing of panels
1354166124Srafan    |----&gt; panel_simple.c    -- A simple panel example
1355166124Srafan
1356166124Srafan  perl
1357262685Sdelphij    |----&gt; 01-10.pl          -- Perl equivalents of first ten example programs</PRE
1358262685Sdelphij><P
1359262685Sdelphij>There is a top level Makefile included in the main directory. It builds all the 
1360262685Sdelphijfiles and puts the ready-to-use exes in demo/exe directory. You can also 
1361262685Sdelphijdo selective make by going into the corresponding directory. Each directory 
1362262685Sdelphijcontains a README file explaining the purpose of each c file in the directory.</P
1363262685Sdelphij><P
1364262685Sdelphij>For every example, I have included path name for the file relative to the 
1365262685Sdelphijexamples directory. </P
1366262685Sdelphij><P
1367262685Sdelphij> If you prefer browsing individual programs, point your browser to 
1368262685Sdelphij<A
1369262685SdelphijHREF="http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/ncurses_programs/"
1370262685SdelphijTARGET="_top"
1371262685Sdelphij>http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/ncurses_programs/</A
1372262685Sdelphij></P
1373262685Sdelphij><P
1374262685Sdelphij>All the programs are released under the same license that is used by ncurses
1375262685Sdelphij(MIT-style). This gives you the ability to do pretty much anything other than
1376262685Sdelphijclaiming them as yours. Feel free to use them in your programs as appropriate.</P
1377262685Sdelphij></DIV
1378262685Sdelphij><DIV
1379262685SdelphijCLASS="SECT2"
1380262685Sdelphij><HR><H3
1381262685SdelphijCLASS="SECT2"
1382262685Sdelphij><A
1383262685SdelphijNAME="OTHERFORMATS"
1384262685Sdelphij>1.6. Other Formats of the document</A
1385262685Sdelphij></H3
1386262685Sdelphij><P
1387262685Sdelphij>This howto is also availabe in various other formats on the tldp.org site.
1388262685SdelphijHere are the links to other formats of this document.</P
1389262685Sdelphij><DIV
1390262685SdelphijCLASS="SECT3"
1391262685Sdelphij><HR><H4
1392262685SdelphijCLASS="SECT3"
1393262685Sdelphij><A
1394262685SdelphijNAME="LISTFORMATS"
1395262685Sdelphij>1.6.1. Readily available formats from tldp.org</A
1396262685Sdelphij></H4
1397262685Sdelphij><P
1398262685Sdelphij></P
1399262685Sdelphij><UL
1400262685Sdelphij><LI
1401262685Sdelphij><P
1402262685Sdelphij><A
1403262685SdelphijHREF="http://www.ibiblio.org/pub/Linux/docs/HOWTO/other-formats/pdf/NCURSES-Programming-HOWTO.pdf"
1404262685SdelphijTARGET="_top"
1405262685Sdelphij>Acrobat PDF Format</A
1406262685Sdelphij></P
1407262685Sdelphij></LI
1408262685Sdelphij><LI
1409262685Sdelphij><P
1410262685Sdelphij><A
1411262685SdelphijHREF="http://www.ibiblio.org/pub/Linux/docs/HOWTO/other-formats/ps/NCURSES-Programming-HOWTO.ps.gz"
1412262685SdelphijTARGET="_top"
1413262685Sdelphij>PostScript Format</A
1414262685Sdelphij></P
1415262685Sdelphij></LI
1416262685Sdelphij><LI
1417262685Sdelphij><P
1418262685Sdelphij><A
1419262685SdelphijHREF="http://www.ibiblio.org/pub/Linux/docs/HOWTO/other-formats/html/NCURSES-Programming-HOWTO-html.tar.gz"
1420262685SdelphijTARGET="_top"
1421262685Sdelphij>In Multiple HTML pages</A
1422262685Sdelphij></P
1423262685Sdelphij></LI
1424262685Sdelphij><LI
1425262685Sdelphij><P
1426262685Sdelphij><A
1427262685SdelphijHREF="http://www.ibiblio.org/pub/Linux/docs/HOWTO/other-formats/html_single/NCURSES-Programming-HOWTO.html"
1428262685SdelphijTARGET="_top"
1429262685Sdelphij>In One big HTML format</A
1430262685Sdelphij></P
1431262685Sdelphij></LI
1432262685Sdelphij></UL
1433262685Sdelphij></DIV
1434262685Sdelphij><DIV
1435262685SdelphijCLASS="SECT3"
1436262685Sdelphij><HR><H4
1437262685SdelphijCLASS="SECT3"
1438262685Sdelphij><A
1439262685SdelphijNAME="BUILDSOURCE"
1440262685Sdelphij>1.6.2. Building from source</A
1441262685Sdelphij></H4
1442262685Sdelphij><P
1443262685Sdelphij>If above links are broken or if you want to experiment with sgml read on.
1444262685Sdelphij<PRE
1445262685SdelphijCLASS="PROGRAMLISTING"
1446262685Sdelphij>&#13;    Get both the source and the tar,gzipped programs, available at
1447166124Srafan        http://cvsview.tldp.org/index.cgi/LDP/howto/docbook/
1448166124Srafan        NCURSES-HOWTO/NCURSES-Programming-HOWTO.sgml
1449166124Srafan        http://cvsview.tldp.org/index.cgi/LDP/howto/docbook/
1450166124Srafan        NCURSES-HOWTO/ncurses_programs.tar.gz
1451166124Srafan
1452166124Srafan    Unzip ncurses_programs.tar.gz with
1453166124Srafan    tar zxvf ncurses_programs.tar.gz
1454166124Srafan
1455166124Srafan    Use jade to create various formats. For example if you just want to create
1456166124Srafan    the multiple html files, you would use
1457166124Srafan        jade -t sgml -i html -d &lt;path to docbook html stylesheet&gt;
1458166124Srafan        NCURSES-Programming-HOWTO.sgml
1459166124Srafan    to get pdf, first create a single html file of the HOWTO with 
1460166124Srafan        jade -t sgml -i html -d &lt;path to docbook html stylesheet&gt; -V nochunks
1461166124Srafan        NCURSES-Programming-HOWTO.sgml &gt; NCURSES-ONE-BIG-FILE.html
1462166124Srafan    then use htmldoc to get pdf file with
1463166124Srafan        htmldoc --size universal -t pdf --firstpage p1 -f &lt;output file name.pdf&gt;
1464166124Srafan        NCURSES-ONE-BIG-FILE.html
1465166124Srafan    for ps, you would use
1466166124Srafan        htmldoc --size universal -t ps --firstpage p1 -f &lt;output file name.ps&gt;
1467262685Sdelphij        NCURSES-ONE-BIG-FILE.html</PRE
1468262685Sdelphij></P
1469262685Sdelphij><P
1470262685Sdelphij>See <A
1471262685SdelphijHREF="http://www.tldp.org/LDP/LDP-Author-Guide/"
1472262685SdelphijTARGET="_top"
1473262685Sdelphij>LDP Author guide</A
1474262685Sdelphij> for more details. If all else failes, mail me at 
1475262685Sdelphij<A
1476262685SdelphijHREF="ppadala@gmail.com"
1477262685SdelphijTARGET="_top"
1478262685Sdelphij>ppadala@gmail.com</A
1479262685Sdelphij></P
1480262685Sdelphij></DIV
1481262685Sdelphij></DIV
1482262685Sdelphij><DIV
1483262685SdelphijCLASS="SECT2"
1484262685Sdelphij><HR><H3
1485262685SdelphijCLASS="SECT2"
1486262685Sdelphij><A
1487262685SdelphijNAME="CREDITS"
1488262685Sdelphij>1.7. Credits</A
1489262685Sdelphij></H3
1490262685Sdelphij><P
1491262685Sdelphij>I thank <A
1492262685SdelphijHREF="mailto:sharath_1@usa.net"
1493262685SdelphijTARGET="_top"
1494262685Sdelphij>Sharath</A
1495262685Sdelphij> and Emre Akbas for
1496262685Sdelphijhelping me with few sections. The introduction was initially written by sharath.
1497262685SdelphijI rewrote it with few excerpts taken from his initial work. Emre helped in
1498262685Sdelphijwriting printw and scanw sections.</P
1499262685Sdelphij><P
1500262685Sdelphij>Perl equivalents of the example programs are contributed by <A
1501262685SdelphijHREF="mailto:Aratnaweera@virtusa.com"
1502262685SdelphijTARGET="_top"
1503262685Sdelphij>Anuradha Ratnaweera</A
1504262685Sdelphij>. </P
1505262685Sdelphij><P
1506262685Sdelphij>Then comes <A
1507262685SdelphijHREF="mailto:parimi@ece.arizona.edu"
1508262685SdelphijTARGET="_top"
1509262685Sdelphij>Ravi Parimi</A
1510262685Sdelphij>, my
1511262685Sdelphijdearest friend, who has been on this project before even one line was written.
1512262685SdelphijHe constantly bombarded me with suggestions and patiently reviewed the whole
1513262685Sdelphijtext.  He also checked each program on Linux and Solaris. </P
1514262685Sdelphij></DIV
1515262685Sdelphij><DIV
1516262685SdelphijCLASS="SECT2"
1517262685Sdelphij><HR><H3
1518262685SdelphijCLASS="SECT2"
1519262685Sdelphij><A
1520262685SdelphijNAME="WISHLIST"
1521262685Sdelphij>1.8. Wish List</A
1522262685Sdelphij></H3
1523262685Sdelphij><P
1524262685Sdelphij>This is the wish list, in the order of priority. If you have a wish or you want
1525262685Sdelphijto work on completing the wish, mail <A
1526262685SdelphijHREF="mailto:ppadala@gmail.com"
1527262685SdelphijTARGET="_top"
1528262685Sdelphij>me</A
1529262685Sdelphij>. </P
1530262685Sdelphij><P
1531262685Sdelphij></P
1532262685Sdelphij><UL
1533262685Sdelphij><LI
1534262685Sdelphij><P
1535262685Sdelphij>Add examples to last parts of forms section.</P
1536262685Sdelphij></LI
1537262685Sdelphij><LI
1538262685Sdelphij><P
1539262685Sdelphij>Prepare a Demo showing all the programs and allow the user to browse through
1540262685Sdelphijdescription of each program. Let the user compile and see the program in action.
1541262685SdelphijA dialog based interface is preferred.</P
1542262685Sdelphij></LI
1543262685Sdelphij><LI
1544262685Sdelphij><P
1545262685Sdelphij>Add debug info. _tracef, _tracemouse stuff.</P
1546262685Sdelphij></LI
1547262685Sdelphij><LI
1548262685Sdelphij><P
1549262685Sdelphij>Accessing termcap, terminfo using functions provided by ncurses
1550262685Sdelphijpackage.</P
1551262685Sdelphij></LI
1552262685Sdelphij><LI
1553262685Sdelphij><P
1554262685Sdelphij>Working on two terminals simultaneously.</P
1555262685Sdelphij></LI
1556262685Sdelphij><LI
1557262685Sdelphij><P
1558262685Sdelphij>Add more stuff to miscellaneous section.</P
1559262685Sdelphij></LI
1560262685Sdelphij></UL
1561262685Sdelphij></DIV
1562262685Sdelphij><DIV
1563262685SdelphijCLASS="SECT2"
1564262685Sdelphij><HR><H3
1565262685SdelphijCLASS="SECT2"
1566262685Sdelphij><A
1567262685SdelphijNAME="COPYRIGHT"
1568262685Sdelphij>1.9. Copyright</A
1569262685Sdelphij></H3
1570262685Sdelphij><P
1571262685Sdelphij>Copyright &copy; 2001 by Pradeep Padala. </P
1572262685Sdelphij><P
1573262685Sdelphij>Permission is hereby granted, free of charge, to any person obtaining a copy
1574262685Sdelphijof this software and associated documentation files (the "Software"), to deal
1575262685Sdelphijin the Software without restriction, including without limitation the rights
1576262685Sdelphijto use, copy, modify, merge, publish, distribute, distribute with
1577262685Sdelphijmodifications, sublicense, and/or sell copies of the Software, and to permit
1578262685Sdelphijpersons to whom the Software is furnished to do so, subject to the following
1579262685Sdelphijconditions:</P
1580262685Sdelphij><P
1581262685Sdelphij>The above copyright notice and this permission notice shall be included in all
1582262685Sdelphijcopies or substantial portions of the Software.</P
1583262685Sdelphij><P
1584262685Sdelphij>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1585262685SdelphijIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1586262685SdelphijFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1587262685SdelphijABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
1588262685SdelphijWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
1589262685SdelphijIN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</P
1590262685Sdelphij><P
1591262685Sdelphij>Except as contained in this notice, the name(s) of the above copyright holders
1592262685Sdelphijshall not be used in advertising or otherwise to promote the sale, use or
1593262685Sdelphijother dealings in this Software without prior written authorization. </P
1594262685Sdelphij></DIV
1595262685Sdelphij></DIV
1596262685Sdelphij><DIV
1597262685SdelphijCLASS="SECT1"
1598262685Sdelphij><HR><H2
1599262685SdelphijCLASS="SECT1"
1600262685Sdelphij><A
1601262685SdelphijNAME="HELLOWORLD"
1602262685Sdelphij>2. Hello World !!!</A
1603262685Sdelphij></H2
1604262685Sdelphij><P
1605262685Sdelphij>Welcome to the world of curses. Before we plunge into the library and look into
1606262685Sdelphijits various features, let's write a simple program and say
1607262685Sdelphijhello to the world. </P
1608262685Sdelphij><DIV
1609262685SdelphijCLASS="SECT2"
1610262685Sdelphij><HR><H3
1611262685SdelphijCLASS="SECT2"
1612262685Sdelphij><A
1613262685SdelphijNAME="COMPILECURSES"
1614262685Sdelphij>2.1. Compiling With the NCURSES Library</A
1615262685Sdelphij></H3
1616262685Sdelphij><P
1617262685Sdelphij>To use ncurses library functions, you have to include ncurses.h in your
1618262685Sdelphijprograms. To link the
1619262685Sdelphijprogram with ncurses the flag -lncurses should be added.</P
1620262685Sdelphij><PRE
1621262685SdelphijCLASS="PROGRAMLISTING"
1622262685Sdelphij>    #include &lt;ncurses.h&gt;
1623166124Srafan    .
1624166124Srafan    .
1625166124Srafan    .
1626166124Srafan
1627262685Sdelphij    compile and link: gcc &lt;program file&gt; -lncurses</PRE
1628262685Sdelphij><DIV
1629262685SdelphijCLASS="EXAMPLE"
1630262685Sdelphij><A
1631262685SdelphijNAME="BHW"
1632262685Sdelphij></A
1633262685Sdelphij><P
1634262685Sdelphij><B
1635262685Sdelphij>Example 1.  The Hello World !!! Program </B
1636262685Sdelphij></P
1637262685Sdelphij><PRE
1638262685SdelphijCLASS="PROGRAMLISTING"
1639262685Sdelphij><SPAN
1640262685SdelphijCLASS="INLINEMEDIAOBJECT"
1641262685Sdelphij>#include &#60;ncurses.h&#62;
1642166124Srafan
1643166124Srafanint main()
1644262685Sdelphij{	
1645262685Sdelphij	initscr();			/* Start curses mode 		  */
1646262685Sdelphij	printw("Hello World !!!");	/* Print Hello World		  */
1647262685Sdelphij	refresh();			/* Print it on to the real screen */
1648262685Sdelphij	getch();			/* Wait for user input */
1649262685Sdelphij	endwin();			/* End curses mode		  */
1650166124Srafan
1651262685Sdelphij	return 0;
1652262685Sdelphij}</SPAN
1653262685Sdelphij></PRE
1654262685Sdelphij></DIV
1655262685Sdelphij></DIV
1656262685Sdelphij><DIV
1657262685SdelphijCLASS="SECT2"
1658262685Sdelphij><HR><H3
1659262685SdelphijCLASS="SECT2"
1660262685Sdelphij><A
1661262685SdelphijNAME="DISSECTION"
1662262685Sdelphij>2.2. Dissection</A
1663262685Sdelphij></H3
1664262685Sdelphij><P
1665262685Sdelphij> 
1666262685SdelphijThe above program prints "Hello World !!!" to the screen and exits. This 
1667262685Sdelphijprogram shows how to initialize curses and do screen manipulation and 
1668262685Sdelphijend curses mode. Let's dissect it line by line. </P
1669262685Sdelphij><DIV
1670262685SdelphijCLASS="SECT3"
1671262685Sdelphij><HR><H4
1672262685SdelphijCLASS="SECT3"
1673262685Sdelphij><A
1674262685SdelphijNAME="ABOUT-INITSCR"
1675262685Sdelphij>2.2.1. About initscr()</A
1676262685Sdelphij></H4
1677262685Sdelphij><P
1678262685Sdelphij>The function initscr() initializes the terminal in curses mode.  In some 
1679262685Sdelphijimplementations, it clears the screen and presents a blank screen. To do any 
1680262685Sdelphijscreen manipulation using curses package this has to be called first. This
1681262685Sdelphijfunction initializes the curses system and allocates memory for our present
1682262685Sdelphijwindow (called <TT
1683262685SdelphijCLASS="LITERAL"
1684262685Sdelphij>stdscr</TT
1685262685Sdelphij>) and some other data-structures. Under extreme
1686262685Sdelphijcases this function might fail due to insufficient memory to allocate memory
1687262685Sdelphijfor curses library's data structures. </P
1688262685Sdelphij><P
1689262685Sdelphij> 
1690262685SdelphijAfter this is done, we can do a variety of initializations to customize
1691262685Sdelphijour curses settings. These details will be explained <A
1692262685SdelphijHREF="#INIT"
1693262685Sdelphij>later </A
1694262685Sdelphij>.</P
1695262685Sdelphij></DIV
1696262685Sdelphij><DIV
1697262685SdelphijCLASS="SECT3"
1698262685Sdelphij><HR><H4
1699262685SdelphijCLASS="SECT3"
1700262685Sdelphij><A
1701262685SdelphijNAME="MYST-REFRESH"
1702262685Sdelphij>2.2.2. The mysterious refresh()</A
1703262685Sdelphij></H4
1704262685Sdelphij><P
1705262685Sdelphij>The next line printw prints the string "Hello World !!!" on to the screen. This
1706262685Sdelphijfunction is analogous to normal printf in all respects except that it prints
1707262685Sdelphijthe data on a window called stdscr at the current (y,x) co-ordinates. Since our
1708262685Sdelphijpresent co-ordinates are at 0,0 the string is printed at the left hand corner
1709262685Sdelphijof the window.</P
1710262685Sdelphij><P
1711262685Sdelphij>This brings us to that mysterious refresh(). Well, when we called printw 
1712262685Sdelphijthe data is actually written to an imaginary window, which is not updated 
1713262685Sdelphijon the screen yet. The job of printw is to update a few flags
1714262685Sdelphijand data structures and write the data to a buffer corresponding to stdscr.
1715262685SdelphijIn order to show it on the screen, we need to call refresh() and tell the
1716262685Sdelphijcurses system to dump the contents on the screen.</P
1717262685Sdelphij><P
1718262685Sdelphij>The philosophy behind all this is to allow the programmer to do multiple updates
1719262685Sdelphijon the imaginary screen or windows and do a refresh once all his screen update
1720262685Sdelphijis done. refresh() checks the window and updates only the portion which has been
1721262685Sdelphijchanged. This improves performance and offers greater flexibility too. But, it is
1722262685Sdelphijsometimes frustrating to beginners. A common mistake committed by beginners is
1723262685Sdelphijto forget to call refresh() after they did some update through printw() class of
1724262685Sdelphijfunctions. I still forget to add it sometimes :-) </P
1725262685Sdelphij></DIV
1726262685Sdelphij><DIV
1727262685SdelphijCLASS="SECT3"
1728262685Sdelphij><HR><H4
1729262685SdelphijCLASS="SECT3"
1730262685Sdelphij><A
1731262685SdelphijNAME="ABOUT-ENDWIN"
1732262685Sdelphij>2.2.3. About endwin()</A
1733262685Sdelphij></H4
1734262685Sdelphij><P
1735262685Sdelphij>And finally don't forget to end the curses mode. Otherwise your terminal might
1736262685Sdelphijbehave strangely after the program quits. endwin() frees the memory taken by 
1737262685Sdelphijcurses sub-system and its data structures and puts the terminal in normal 
1738262685Sdelphijmode. This function must be called after you are done with the curses mode. </P
1739262685Sdelphij></DIV
1740262685Sdelphij></DIV
1741262685Sdelphij></DIV
1742262685Sdelphij><DIV
1743262685SdelphijCLASS="SECT1"
1744262685Sdelphij><HR><H2
1745262685SdelphijCLASS="SECT1"
1746262685Sdelphij><A
1747262685SdelphijNAME="GORY"
1748262685Sdelphij>3. The Gory Details</A
1749262685Sdelphij></H2
1750262685Sdelphij><P
1751262685Sdelphij>Now that we have seen how to write a simple curses program let's get into the
1752262685Sdelphijdetails. There are many functions that help customize what you see on screen and
1753262685Sdelphijmany features which can be put to full use. </P
1754262685Sdelphij><P
1755262685Sdelphij>Here we go...</P
1756262685Sdelphij></DIV
1757262685Sdelphij><DIV
1758262685SdelphijCLASS="SECT1"
1759262685Sdelphij><HR><H2
1760262685SdelphijCLASS="SECT1"
1761262685Sdelphij><A
1762262685SdelphijNAME="INIT"
1763262685Sdelphij>4. Initialization</A
1764262685Sdelphij></H2
1765262685Sdelphij><P
1766262685Sdelphij>We now know that to initialize curses system the function initscr() has to be
1767262685Sdelphijcalled.  There are functions which can be called after this initialization to
1768262685Sdelphijcustomize our curses session. We may ask the curses system to set the terminal
1769262685Sdelphijin raw mode or initialize color or initialize the mouse etc.. Let's discuss some
1770262685Sdelphijof the functions that are normally called immediately after initscr();</P
1771262685Sdelphij><DIV
1772262685SdelphijCLASS="SECT2"
1773262685Sdelphij><HR><H3
1774262685SdelphijCLASS="SECT2"
1775262685Sdelphij><A
1776262685SdelphijNAME="ABOUTINIT"
1777262685Sdelphij>4.1. Initialization functions</A
1778262685Sdelphij></H3
1779262685Sdelphij><P
1780262685Sdelphij> </P
1781262685Sdelphij></DIV
1782262685Sdelphij><DIV
1783262685SdelphijCLASS="SECT2"
1784262685Sdelphij><HR><H3
1785262685SdelphijCLASS="SECT2"
1786262685Sdelphij><A
1787262685SdelphijNAME="RAWCBREAK"
1788262685Sdelphij>4.2. raw() and cbreak()</A
1789262685Sdelphij></H3
1790262685Sdelphij><P
1791262685Sdelphij>Normally the terminal driver buffers the characters a user types until a new
1792262685Sdelphijline or carriage return is encountered. But most programs require that the
1793262685Sdelphijcharacters be available as soon as the user types them. The above two functions
1794262685Sdelphijare used to disable line buffering. The difference between these two functions
1795262685Sdelphijis in the way control characters like suspend (CTRL-Z), interrupt and quit
1796262685Sdelphij(CTRL-C) are passed to the program. In the raw() mode these characters are
1797262685Sdelphijdirectly passed to the program without generating a signal. In the
1798262685Sdelphij<TT
1799262685SdelphijCLASS="LITERAL"
1800262685Sdelphij>cbreak()</TT
1801262685Sdelphij> mode these control characters are
1802262685Sdelphijinterpreted as any other character by the terminal driver. I personally prefer
1803262685Sdelphijto use raw() as I can exercise greater control over what the user does.</P
1804262685Sdelphij></DIV
1805262685Sdelphij><DIV
1806262685SdelphijCLASS="SECT2"
1807262685Sdelphij><HR><H3
1808262685SdelphijCLASS="SECT2"
1809262685Sdelphij><A
1810262685SdelphijNAME="ECHONOECHO"
1811262685Sdelphij>4.3. echo() and noecho()</A
1812262685Sdelphij></H3
1813262685Sdelphij><P
1814262685Sdelphij> 
1815262685SdelphijThese functions control the echoing of characters typed by the user to the
1816262685Sdelphijterminal. <TT
1817262685SdelphijCLASS="LITERAL"
1818262685Sdelphij>noecho()</TT
1819262685Sdelphij> switches off echoing. The
1820262685Sdelphijreason you might want to do this is to gain more control over echoing or to
1821262685Sdelphijsuppress unnecessary echoing while taking input from the user through the
1822262685Sdelphijgetch() etc. functions. Most of the interactive programs call
1823262685Sdelphij<TT
1824262685SdelphijCLASS="LITERAL"
1825262685Sdelphij>noecho()</TT
1826262685Sdelphij> at initialization and do the echoing
1827262685Sdelphijof characters in a controlled manner. It gives the programmer the flexibility
1828262685Sdelphijof echoing characters at any place in the window without updating current (y,x)
1829262685Sdelphijco-ordinates. </P
1830262685Sdelphij></DIV
1831262685Sdelphij><DIV
1832262685SdelphijCLASS="SECT2"
1833262685Sdelphij><HR><H3
1834262685SdelphijCLASS="SECT2"
1835262685Sdelphij><A
1836262685SdelphijNAME="KEYPAD"
1837262685Sdelphij>4.4. keypad()</A
1838262685Sdelphij></H3
1839262685Sdelphij><P
1840262685Sdelphij>This is my favorite initialization function. It enables the reading of function
1841262685Sdelphijkeys like F1, F2, arrow keys etc. Almost every interactive program enables this,
1842262685Sdelphijas arrow keys are a major part of any User Interface. Do
1843262685Sdelphij<TT
1844262685SdelphijCLASS="LITERAL"
1845262685Sdelphij>keypad(stdscr, TRUE) </TT
1846262685Sdelphij> to enable this feature
1847262685Sdelphijfor the regular screen (stdscr). You will learn more about key management in
1848262685Sdelphijlater sections of this document.</P
1849262685Sdelphij></DIV
1850262685Sdelphij><DIV
1851262685SdelphijCLASS="SECT2"
1852262685Sdelphij><HR><H3
1853262685SdelphijCLASS="SECT2"
1854262685Sdelphij><A
1855262685SdelphijNAME="HALFDELAY"
1856262685Sdelphij>4.5. halfdelay()</A
1857262685Sdelphij></H3
1858262685Sdelphij><P
1859262685Sdelphij>This function, though not used very often, is a useful one at times.
1860262685Sdelphijhalfdelay()is called to enable the half-delay mode, which is similar to the
1861262685Sdelphijcbreak() mode in that characters typed are immediately available to program.
1862262685SdelphijHowever, it waits for 'X' tenths of a second for input and then returns ERR, if
1863262685Sdelphijno input is available. 'X' is the timeout value passed to the function
1864262685Sdelphijhalfdelay(). This function is useful when you want to ask the user for input,
1865262685Sdelphijand if he doesn't respond with in certain time, we can do some thing else. One
1866262685Sdelphijpossible example is a timeout at the password prompt. </P
1867262685Sdelphij></DIV
1868262685Sdelphij><DIV
1869262685SdelphijCLASS="SECT2"
1870262685Sdelphij><HR><H3
1871262685SdelphijCLASS="SECT2"
1872262685Sdelphij><A
1873262685SdelphijNAME="MISCINIT"
1874262685Sdelphij>4.6. Miscellaneous Initialization functions</A
1875262685Sdelphij></H3
1876262685Sdelphij><P
1877262685Sdelphij>There are few more functions which are called at initialization to
1878262685Sdelphijcustomize curses behavior. They are not used as extensively as those mentioned 
1879262685Sdelphijabove. Some of them are explained where appropriate.</P
1880262685Sdelphij></DIV
1881262685Sdelphij><DIV
1882262685SdelphijCLASS="SECT2"
1883262685Sdelphij><HR><H3
1884262685SdelphijCLASS="SECT2"
1885262685Sdelphij><A
1886262685SdelphijNAME="INITEX"
1887262685Sdelphij>4.7. An Example</A
1888262685Sdelphij></H3
1889262685Sdelphij><P
1890262685Sdelphij>Let's write a program which will clarify the usage of these functions.</P
1891262685Sdelphij><DIV
1892262685SdelphijCLASS="EXAMPLE"
1893262685Sdelphij><A
1894262685SdelphijNAME="BINFU"
1895262685Sdelphij></A
1896262685Sdelphij><P
1897262685Sdelphij><B
1898262685Sdelphij>Example 2.  Initialization Function Usage example </B
1899262685Sdelphij></P
1900262685Sdelphij><PRE
1901262685SdelphijCLASS="PROGRAMLISTING"
1902262685Sdelphij><SPAN
1903262685SdelphijCLASS="INLINEMEDIAOBJECT"
1904262685Sdelphij>#include &#60;ncurses.h&#62;
1905166124Srafan
1906166124Srafanint main()
1907262685Sdelphij{	int ch;
1908166124Srafan
1909262685Sdelphij	initscr();			/* Start curses mode 		*/
1910262685Sdelphij	raw();				/* Line buffering disabled	*/
1911262685Sdelphij	keypad(stdscr, TRUE);		/* We get F1, F2 etc..		*/
1912262685Sdelphij	noecho();			/* Don't echo() while we do getch */
1913166124Srafan
1914262685Sdelphij    	printw("Type any character to see it in bold\n");
1915262685Sdelphij	ch = getch();			/* If raw() hadn't been called
1916262685Sdelphij					 * we have to press enter before it
1917262685Sdelphij					 * gets to the program 		*/
1918262685Sdelphij	if(ch == KEY_F(1))		/* Without keypad enabled this will */
1919262685Sdelphij		printw("F1 Key pressed");/*  not get to us either	*/
1920262685Sdelphij					/* Without noecho() some ugly escape
1921262685Sdelphij					 * charachters might have been printed
1922262685Sdelphij					 * on screen			*/
1923262685Sdelphij	else
1924262685Sdelphij	{	printw("The pressed key is ");
1925262685Sdelphij		attron(A_BOLD);
1926262685Sdelphij		printw("%c", ch);
1927262685Sdelphij		attroff(A_BOLD);
1928262685Sdelphij	}
1929262685Sdelphij	refresh();			/* Print it on to the real screen */
1930262685Sdelphij    	getch();			/* Wait for user input */
1931262685Sdelphij	endwin();			/* End curses mode		  */
1932166124Srafan
1933262685Sdelphij	return 0;
1934262685Sdelphij}</SPAN
1935262685Sdelphij></PRE
1936262685Sdelphij></DIV
1937262685Sdelphij><P
1938262685Sdelphij>This program is self-explanatory. But I used functions which aren't explained
1939262685Sdelphijyet. The function <TT
1940262685SdelphijCLASS="LITERAL"
1941262685Sdelphij>getch()</TT
1942262685Sdelphij> is used to get a
1943262685Sdelphijcharacter from user. It is equivalent to normal
1944262685Sdelphij<TT
1945262685SdelphijCLASS="LITERAL"
1946262685Sdelphij>getchar()</TT
1947262685Sdelphij> except that we can disable the line
1948262685Sdelphijbuffering to avoid &lt;enter&gt; after input. Look for more about
1949262685Sdelphij<TT
1950262685SdelphijCLASS="LITERAL"
1951262685Sdelphij>getch()</TT
1952262685Sdelphij>and reading keys in the <A
1953262685SdelphijHREF="#KEYS"
1954262685Sdelphij> key management section </A
1955262685Sdelphij>. The functions attron and attroff 
1956262685Sdelphijare used to switch some attributes on and off respectively.  In the example I 
1957262685Sdelphijused them to print the character in bold. These functions are explained in detail
1958262685Sdelphijlater.</P
1959262685Sdelphij></DIV
1960262685Sdelphij></DIV
1961262685Sdelphij><DIV
1962262685SdelphijCLASS="SECT1"
1963262685Sdelphij><HR><H2
1964262685SdelphijCLASS="SECT1"
1965262685Sdelphij><A
1966262685SdelphijNAME="AWORDWINDOWS"
1967262685Sdelphij>5. A Word about Windows</A
1968262685Sdelphij></H2
1969262685Sdelphij><P
1970262685Sdelphij> 
1971262685SdelphijBefore we plunge into the myriad ncurses functions, let me clear few things
1972262685Sdelphijabout windows. Windows are explained in detail in following <A
1973262685SdelphijHREF="#WINDOWS"
1974262685Sdelphij> sections </A
1975262685Sdelphij></P
1976262685Sdelphij><P
1977262685Sdelphij>A Window is an imaginary screen defined by curses system. A window does not mean
1978262685Sdelphija bordered window which you usually see on Win9X platforms. When curses is
1979262685Sdelphijinitialized, it creates a default window named
1980262685Sdelphij<TT
1981262685SdelphijCLASS="LITERAL"
1982262685Sdelphij>stdscr</TT
1983262685Sdelphij> which represents your 80x25 (or the size
1984262685Sdelphijof window in which you are running) screen.  If you are doing simple tasks like
1985262685Sdelphijprinting few strings, reading input etc., you can safely use this single window
1986262685Sdelphijfor all of your purposes. You can also create windows and call functions which
1987262685Sdelphijexplicitly work on the specified window.</P
1988262685Sdelphij><P
1989262685Sdelphij>For example, if you call</P
1990262685Sdelphij><PRE
1991262685SdelphijCLASS="PROGRAMLISTING"
1992262685Sdelphij>    printw("Hi There !!!");
1993262685Sdelphij    refresh();</PRE
1994262685Sdelphij><P
1995262685Sdelphij>It prints the string on stdscr at the present cursor position. Similarly the 
1996262685Sdelphijcall to refresh(), works on stdscr only. </P
1997262685Sdelphij><P
1998262685Sdelphij>Say you have created <A
1999262685SdelphijHREF="#WINDOWS"
2000262685Sdelphij>windows</A
2001262685Sdelphij> then you have to 
2002262685Sdelphijcall a function with a 'w' added to the usual function.</P
2003262685Sdelphij><PRE
2004262685SdelphijCLASS="PROGRAMLISTING"
2005262685Sdelphij>    wprintw(win, "Hi There !!!");
2006262685Sdelphij    wrefresh(win);</PRE
2007262685Sdelphij><P
2008262685Sdelphij>As you will see in the rest of the document, naming of functions follow the
2009262685Sdelphijsame convention. For each function there usually are three more functions.</P
2010262685Sdelphij><PRE
2011262685SdelphijCLASS="PROGRAMLISTING"
2012262685Sdelphij>    printw(string);        /* Print on stdscr at present cursor position */
2013166124Srafan    mvprintw(y, x, string);/* Move to (y, x) then print string     */
2014166124Srafan    wprintw(win, string);  /* Print on window win at present cursor position */
2015166124Srafan                           /* in the window */
2016166124Srafan    mvwprintw(win, y, x, string);   /* Move to (y, x) relative to window */
2017262685Sdelphij                                    /* co-ordinates and then print         */</PRE
2018262685Sdelphij><P
2019262685Sdelphij>Usually the w-less functions are macros which expand to corresponding w-function
2020262685Sdelphijwith stdscr as the window parameter.</P
2021262685Sdelphij></DIV
2022262685Sdelphij><DIV
2023262685SdelphijCLASS="SECT1"
2024262685Sdelphij><HR><H2
2025262685SdelphijCLASS="SECT1"
2026262685Sdelphij><A
2027262685SdelphijNAME="PRINTW"
2028262685Sdelphij>6. Output functions</A
2029262685Sdelphij></H2
2030262685Sdelphij><P
2031262685Sdelphij>I guess you can't wait any more to see some action. Back to our odyssey of
2032262685Sdelphijcurses functions. Now that curses is initialized, let's interact with
2033262685Sdelphijworld.</P
2034262685Sdelphij><P
2035262685Sdelphij>There are three classes of functions which you can use to do output on screen.
2036262685Sdelphij<P
2037262685Sdelphij></P
2038262685Sdelphij><OL
2039262685SdelphijTYPE="1"
2040262685Sdelphij><LI
2041262685Sdelphij><P
2042262685Sdelphij>addch() class: Print single character with attributes </P
2043262685Sdelphij></LI
2044262685Sdelphij><LI
2045262685Sdelphij><P
2046262685Sdelphij>printw() class: Print formatted output similar to printf()</P
2047262685Sdelphij></LI
2048262685Sdelphij><LI
2049262685Sdelphij><P
2050262685Sdelphij>addstr() class: Print strings</P
2051262685Sdelphij></LI
2052262685Sdelphij></OL
2053262685Sdelphij></P
2054262685Sdelphij><P
2055262685Sdelphij>These functions can be used interchangeably and it's a matter of style as to
2056262685Sdelphijwhich class is used. Let's see each one in detail.</P
2057262685Sdelphij><DIV
2058262685SdelphijCLASS="SECT2"
2059262685Sdelphij><HR><H3
2060262685SdelphijCLASS="SECT2"
2061262685Sdelphij><A
2062262685SdelphijNAME="ADDCHCLASS"
2063262685Sdelphij>6.1. addch() class of functions</A
2064262685Sdelphij></H3
2065262685Sdelphij><P
2066262685Sdelphij>These functions put a single character into the current cursor location and
2067262685Sdelphijadvance the position of the cursor. You can give the character to be printed but
2068262685Sdelphijthey usually are used to print a character with some attributes.  Attributes are
2069262685Sdelphijexplained in detail in later <A
2070262685SdelphijHREF="#ATTRIB"
2071262685Sdelphij> sections </A
2072262685Sdelphij> of the
2073262685Sdelphijdocument. If a character is associated with an attribute(bold, reverse video
2074262685Sdelphijetc.), when curses prints the character, it is printed in that attribute.</P
2075262685Sdelphij><P
2076262685Sdelphij>In order to combine a character with some attributes, you have two options:</P
2077262685Sdelphij><P
2078262685Sdelphij></P
2079262685Sdelphij><UL
2080262685Sdelphij><LI
2081262685Sdelphij><P
2082262685Sdelphij>By OR'ing a single character with the desired attribute macros. These attribute
2083262685Sdelphijmacros could be found in the header file
2084262685Sdelphij<TT
2085262685SdelphijCLASS="LITERAL"
2086262685Sdelphij>ncurses.h</TT
2087262685Sdelphij>. For example, you want to print a
2088262685Sdelphijcharacter ch(of type char) bold and underlined, you would call addch() as below.
2089262685Sdelphij<PRE
2090262685SdelphijCLASS="PROGRAMLISTING"
2091262685Sdelphij>    addch(ch | A_BOLD | A_UNDERLINE);</PRE
2092262685Sdelphij></P
2093262685Sdelphij></LI
2094262685Sdelphij><LI
2095262685Sdelphij><P
2096262685Sdelphij>By using functions like <TT
2097262685SdelphijCLASS="LITERAL"
2098262685Sdelphij>attrset(),attron(),attroff()</TT
2099262685Sdelphij>. These functions are explained in the <A
2100262685SdelphijHREF="#ATTRIB"
2101262685Sdelphij>Attributes</A
2102262685Sdelphij> section. Briefly, they manipulate the current attributes of 
2103262685Sdelphijthe given window. Once set, the character printed in the window are associated 
2104262685Sdelphijwith the attributes until it is turned off.</P
2105262685Sdelphij></LI
2106262685Sdelphij></UL
2107262685Sdelphij><P
2108262685Sdelphij>Additionally, <TT
2109262685SdelphijCLASS="LITERAL"
2110262685Sdelphij>curses</TT
2111262685Sdelphij> provides some special
2112262685Sdelphijcharacters for character-based graphics. You can draw tables, horizontal or
2113262685Sdelphijvertical lines, etc. You can find all avaliable characters in the header file
2114262685Sdelphij<TT
2115262685SdelphijCLASS="LITERAL"
2116262685Sdelphij>ncurses.h</TT
2117262685Sdelphij>.  Try looking for macros beginning
2118262685Sdelphijwith <TT
2119262685SdelphijCLASS="LITERAL"
2120262685Sdelphij>ACS_</TT
2121262685Sdelphij> in this file. </P
2122262685Sdelphij></DIV
2123262685Sdelphij><DIV
2124262685SdelphijCLASS="SECT2"
2125262685Sdelphij><HR><H3
2126262685SdelphijCLASS="SECT2"
2127262685Sdelphij><A
2128262685SdelphijNAME="AEN298"
2129262685Sdelphij>6.2. mvaddch(), waddch() and mvwaddch()</A
2130262685Sdelphij></H3
2131262685Sdelphij><P
2132262685Sdelphij><TT
2133262685SdelphijCLASS="LITERAL"
2134262685Sdelphij>mvaddch()</TT
2135262685Sdelphij> is used to move the cursor to a 
2136262685Sdelphijgiven point, and then print. Thus, the calls:
2137262685Sdelphij<PRE
2138262685SdelphijCLASS="PROGRAMLISTING"
2139262685Sdelphij>    move(row,col);    /* moves the cursor to row<SPAN
2140262685SdelphijCLASS="emphasis"
2141262685Sdelphij><I
2142262685SdelphijCLASS="EMPHASIS"
2143262685Sdelphij>th</I
2144262685Sdelphij></SPAN
2145262685Sdelphij> row and col<SPAN
2146262685SdelphijCLASS="emphasis"
2147262685Sdelphij><I
2148262685SdelphijCLASS="EMPHASIS"
2149262685Sdelphij>th</I
2150262685Sdelphij></SPAN
2151262685Sdelphij> column */
2152262685Sdelphij    addch(ch);</PRE
2153262685Sdelphij>
2154166124Srafancan be replaced by
2155262685Sdelphij<PRE
2156262685SdelphijCLASS="PROGRAMLISTING"
2157262685Sdelphij>    mvaddch(row,col,ch);</PRE
2158262685Sdelphij></P
2159262685Sdelphij><P
2160262685Sdelphij><TT
2161262685SdelphijCLASS="LITERAL"
2162262685Sdelphij>waddch()</TT
2163262685Sdelphij> is similar to
2164262685Sdelphij<TT
2165262685SdelphijCLASS="LITERAL"
2166262685Sdelphij>addch()</TT
2167262685Sdelphij>, except that it adds a character into
2168262685Sdelphijthe given window. (Note that <TT
2169262685SdelphijCLASS="LITERAL"
2170262685Sdelphij>addch()</TT
2171262685Sdelphij> adds a
2172262685Sdelphijcharacter into the window <TT
2173262685SdelphijCLASS="LITERAL"
2174262685Sdelphij>stdscr</TT
2175262685Sdelphij>.)</P
2176262685Sdelphij><P
2177262685Sdelphij>In a similar fashion <TT
2178262685SdelphijCLASS="LITERAL"
2179262685Sdelphij>mvwaddch()</TT
2180262685Sdelphij> function is
2181262685Sdelphijused to add a character into the given window at the given coordinates.</P
2182262685Sdelphij><P
2183262685Sdelphij>Now, we are familiar with the basic output function
2184262685Sdelphij<TT
2185262685SdelphijCLASS="LITERAL"
2186262685Sdelphij>addch()</TT
2187262685Sdelphij>. But, if we want to print a string, it
2188262685Sdelphijwould be very annoying to print it character by character. Fortunately,
2189262685Sdelphij<TT
2190262685SdelphijCLASS="LITERAL"
2191262685Sdelphij>ncurses</TT
2192262685Sdelphij> provides <TT
2193262685SdelphijCLASS="LITERAL"
2194262685Sdelphij>printf</TT
2195262685Sdelphij><SPAN
2196262685SdelphijCLASS="emphasis"
2197262685Sdelphij><I
2198262685SdelphijCLASS="EMPHASIS"
2199262685Sdelphij>-like</I
2200262685Sdelphij></SPAN
2201262685Sdelphij> or
2202262685Sdelphij<TT
2203262685SdelphijCLASS="LITERAL"
2204262685Sdelphij>puts</TT
2205262685Sdelphij><SPAN
2206262685SdelphijCLASS="emphasis"
2207262685Sdelphij><I
2208262685SdelphijCLASS="EMPHASIS"
2209262685Sdelphij>-like</I
2210262685Sdelphij></SPAN
2211262685Sdelphij> functions.</P
2212262685Sdelphij></DIV
2213262685Sdelphij><DIV
2214262685SdelphijCLASS="SECT2"
2215262685Sdelphij><HR><H3
2216262685SdelphijCLASS="SECT2"
2217262685Sdelphij><A
2218262685SdelphijNAME="PRINTWCLASS"
2219262685Sdelphij>6.3. printw() class of functions</A
2220262685Sdelphij></H3
2221262685Sdelphij><P
2222262685Sdelphij>These functions are similar to <TT
2223262685SdelphijCLASS="LITERAL"
2224262685Sdelphij>printf()</TT
2225262685Sdelphij> with
2226262685Sdelphijthe added capability of printing at any position on the screen. </P
2227262685Sdelphij><DIV
2228262685SdelphijCLASS="SECT3"
2229262685Sdelphij><HR><H4
2230262685SdelphijCLASS="SECT3"
2231262685Sdelphij><A
2232262685SdelphijNAME="PRINTWMVPRINTW"
2233262685Sdelphij>6.3.1. printw() and mvprintw</A
2234262685Sdelphij></H4
2235262685Sdelphij><P
2236262685Sdelphij>These two functions work much like <TT
2237262685SdelphijCLASS="LITERAL"
2238262685Sdelphij>printf()</TT
2239262685Sdelphij>.
2240262685Sdelphij<TT
2241262685SdelphijCLASS="LITERAL"
2242262685Sdelphij>mvprintw()</TT
2243262685Sdelphij> can be used to move the cursor to a
2244262685Sdelphijposition and then print. If you want to move the cursor first and then print
2245262685Sdelphijusing <TT
2246262685SdelphijCLASS="LITERAL"
2247262685Sdelphij>printw()</TT
2248262685Sdelphij> function, use
2249262685Sdelphij<TT
2250262685SdelphijCLASS="LITERAL"
2251262685Sdelphij>move() </TT
2252262685Sdelphij> first and then use
2253262685Sdelphij<TT
2254262685SdelphijCLASS="LITERAL"
2255262685Sdelphij>printw()</TT
2256262685Sdelphij> though I see no point why one should
2257262685Sdelphijavoid using <TT
2258262685SdelphijCLASS="LITERAL"
2259262685Sdelphij>mvprintw()</TT
2260262685Sdelphij>, you have the
2261262685Sdelphijflexibility to manipulate. </P
2262262685Sdelphij></DIV
2263262685Sdelphij><DIV
2264262685SdelphijCLASS="SECT3"
2265262685Sdelphij><HR><H4
2266262685SdelphijCLASS="SECT3"
2267262685Sdelphij><A
2268262685SdelphijNAME="WPRINTWMVWPRINTW"
2269262685Sdelphij>6.3.2. wprintw() and mvwprintw</A
2270262685Sdelphij></H4
2271262685Sdelphij><P
2272262685Sdelphij>These two functions are similar to above two except that they print in the 
2273262685Sdelphijcorresponding window given as argument. </P
2274262685Sdelphij></DIV
2275262685Sdelphij><DIV
2276262685SdelphijCLASS="SECT3"
2277262685Sdelphij><HR><H4
2278262685SdelphijCLASS="SECT3"
2279262685Sdelphij><A
2280262685SdelphijNAME="VWPRINTW"
2281262685Sdelphij>6.3.3. vwprintw()</A
2282262685Sdelphij></H4
2283262685Sdelphij><P
2284262685Sdelphij>This function is similar to <TT
2285262685SdelphijCLASS="LITERAL"
2286262685Sdelphij>vprintf()</TT
2287262685Sdelphij>. This can
2288262685Sdelphijbe used when variable number of arguments are to be printed.</P
2289262685Sdelphij></DIV
2290262685Sdelphij><DIV
2291262685SdelphijCLASS="SECT3"
2292262685Sdelphij><HR><H4
2293262685SdelphijCLASS="SECT3"
2294262685Sdelphij><A
2295262685SdelphijNAME="SIMPLEPRINTWEX"
2296262685Sdelphij>6.3.4. A Simple printw example</A
2297262685Sdelphij></H4
2298262685Sdelphij><DIV
2299262685SdelphijCLASS="EXAMPLE"
2300262685Sdelphij><A
2301262685SdelphijNAME="BPREX"
2302262685Sdelphij></A
2303262685Sdelphij><P
2304262685Sdelphij><B
2305262685Sdelphij>Example 3.  A Simple printw example </B
2306262685Sdelphij></P
2307262685Sdelphij><PRE
2308262685SdelphijCLASS="PROGRAMLISTING"
2309262685Sdelphij><SPAN
2310262685SdelphijCLASS="INLINEMEDIAOBJECT"
2311262685Sdelphij>#include &#60;ncurses.h&#62;			/* ncurses.h includes stdio.h */  
2312262685Sdelphij#include &#60;string.h&#62; 
2313166124Srafan 
2314166124Srafanint main()
2315166124Srafan{
2316262685Sdelphij char mesg[]="Just a string";		/* message to be appeared on the screen */
2317262685Sdelphij int row,col;				/* to store the number of rows and *
2318262685Sdelphij					 * the number of colums of the screen */
2319262685Sdelphij initscr();				/* start the curses mode */
2320262685Sdelphij getmaxyx(stdscr,row,col);		/* get the number of rows and columns */
2321166124Srafan mvprintw(row/2,(col-strlen(mesg))/2,"%s",mesg);
2322262685Sdelphij                                	/* print the message at the center of the screen */
2323166124Srafan mvprintw(row-2,0,"This screen has %d rows and %d columns\n",row,col);
2324166124Srafan printw("Try resizing your window(if possible) and then run this program again");
2325166124Srafan refresh();
2326166124Srafan getch();
2327166124Srafan endwin();
2328166124Srafan
2329166124Srafan return 0;
2330262685Sdelphij}</SPAN
2331262685Sdelphij></PRE
2332262685Sdelphij></DIV
2333262685Sdelphij><P
2334262685Sdelphij>Above program demonstrates how easy it is to use <TT
2335262685SdelphijCLASS="LITERAL"
2336262685Sdelphij>printw</TT
2337262685Sdelphij>. You just feed the coordinates and the message to be appeared
2338262685Sdelphijon the screen, then it does what you want.</P
2339262685Sdelphij><P
2340262685Sdelphij>The above program introduces us to a new function
2341262685Sdelphij<TT
2342262685SdelphijCLASS="LITERAL"
2343262685Sdelphij>getmaxyx()</TT
2344262685Sdelphij>, a macro defined in
2345262685Sdelphij<TT
2346262685SdelphijCLASS="LITERAL"
2347262685Sdelphij>ncurses.h</TT
2348262685Sdelphij>. It gives the number of columns and
2349262685Sdelphijthe number of rows in a given window.
2350262685Sdelphij<TT
2351262685SdelphijCLASS="LITERAL"
2352262685Sdelphij>getmaxyx()</TT
2353262685Sdelphij> does this by updating the variables
2354262685Sdelphijgiven to it. Since <TT
2355262685SdelphijCLASS="LITERAL"
2356262685Sdelphij>getmaxyx()</TT
2357262685Sdelphij> is not a function
2358262685Sdelphijwe don't pass pointers to it, we just give two integer variables. </P
2359262685Sdelphij></DIV
2360262685Sdelphij></DIV
2361262685Sdelphij><DIV
2362262685SdelphijCLASS="SECT2"
2363262685Sdelphij><HR><H3
2364262685SdelphijCLASS="SECT2"
2365262685Sdelphij><A
2366262685SdelphijNAME="ADDSTRCLASS"
2367262685Sdelphij>6.4. addstr() class of functions</A
2368262685Sdelphij></H3
2369262685Sdelphij><P
2370262685Sdelphij><TT
2371262685SdelphijCLASS="LITERAL"
2372262685Sdelphij>addstr()</TT
2373262685Sdelphij> is used to put a character string into
2374262685Sdelphija given window. This function is similar to calling
2375262685Sdelphij<TT
2376262685SdelphijCLASS="LITERAL"
2377262685Sdelphij>addch()</TT
2378262685Sdelphij> once for each character in a given
2379262685Sdelphijstring. This is true for all output functions. There are other functions from
2380262685Sdelphijthis family such as <TT
2381262685SdelphijCLASS="LITERAL"
2382262685Sdelphij>mvaddstr(),mvwaddstr()</TT
2383262685Sdelphij> and
2384262685Sdelphij<TT
2385262685SdelphijCLASS="LITERAL"
2386262685Sdelphij>waddstr()</TT
2387262685Sdelphij>, which obey the naming convention of
2388262685Sdelphijcurses.(e.g. mvaddstr() is similar to the respective calls move() and then
2389262685Sdelphijaddstr().) Another function of this family is addnstr(), which takes an integer
2390262685Sdelphijparameter(say n) additionally. This function puts at most n characters into the
2391262685Sdelphijscreen. If n is negative, then the entire string will be added. </P
2392262685Sdelphij></DIV
2393262685Sdelphij><DIV
2394262685SdelphijCLASS="SECT2"
2395262685Sdelphij><HR><H3
2396262685SdelphijCLASS="SECT2"
2397262685Sdelphij><A
2398262685SdelphijNAME="ACAUTION"
2399262685Sdelphij>6.5. A word of caution</A
2400262685Sdelphij></H3
2401262685Sdelphij><P
2402262685Sdelphij>All these functions take y co-ordinate first and then x in their arguments.
2403262685SdelphijA common mistake by beginners is to pass x,y in that order. If you are
2404262685Sdelphijdoing too many manipulations of (y,x) co-ordinates, think of dividing the
2405262685Sdelphijscreen into windows and manipulate each one separately. Windows are explained
2406262685Sdelphijin the <A
2407262685SdelphijHREF="#WINDOWS"
2408262685Sdelphij> windows </A
2409262685Sdelphij> section.</P
2410262685Sdelphij></DIV
2411262685Sdelphij></DIV
2412262685Sdelphij><DIV
2413262685SdelphijCLASS="SECT1"
2414262685Sdelphij><HR><H2
2415262685SdelphijCLASS="SECT1"
2416262685Sdelphij><A
2417262685SdelphijNAME="SCANW"
2418262685Sdelphij>7. Input functions</A
2419262685Sdelphij></H2
2420262685Sdelphij><P
2421262685Sdelphij>Well, printing without taking input, is boring. Let's see functions which
2422262685Sdelphijallow us to get input from user. These functions also can be divided into
2423262685Sdelphijthree categories.</P
2424262685Sdelphij><P
2425262685Sdelphij></P
2426262685Sdelphij><OL
2427262685SdelphijTYPE="1"
2428262685Sdelphij><LI
2429262685Sdelphij><P
2430262685Sdelphij>getch() class: Get a character</P
2431262685Sdelphij></LI
2432262685Sdelphij><LI
2433262685Sdelphij><P
2434262685Sdelphij>scanw() class: Get formatted input</P
2435262685Sdelphij></LI
2436262685Sdelphij><LI
2437262685Sdelphij><P
2438262685Sdelphij>getstr() class: Get strings</P
2439262685Sdelphij></LI
2440262685Sdelphij></OL
2441262685Sdelphij><DIV
2442262685SdelphijCLASS="SECT2"
2443262685Sdelphij><HR><H3
2444262685SdelphijCLASS="SECT2"
2445262685Sdelphij><A
2446262685SdelphijNAME="GETCHCLASS"
2447262685Sdelphij>7.1. getch() class of functions</A
2448262685Sdelphij></H3
2449262685Sdelphij><P
2450262685Sdelphij>These functions read a single character from the terminal. But there are several
2451262685Sdelphijsubtle facts to consider. For example if you don't use the function cbreak(),
2452262685Sdelphijcurses will not read your input characters contiguously but will begin read them
2453262685Sdelphijonly after a new line or an EOF is encountered. In order to avoid this, the
2454262685Sdelphijcbreak() function must used so that characters are immediately available to your
2455262685Sdelphijprogram. Another widely used function is noecho(). As the name suggests, when
2456262685Sdelphijthis function is set (used), the characters that are keyed in by the user will
2457262685Sdelphijnot show up on the screen. The two functions cbreak() and noecho() are typical
2458262685Sdelphijexamples of key management.  Functions of this genre are explained in the
2459262685Sdelphij<A
2460262685SdelphijHREF="#KEYS"
2461262685Sdelphij>key management section </A
2462262685Sdelphij>.</P
2463262685Sdelphij></DIV
2464262685Sdelphij><DIV
2465262685SdelphijCLASS="SECT2"
2466262685Sdelphij><HR><H3
2467262685SdelphijCLASS="SECT2"
2468262685Sdelphij><A
2469262685SdelphijNAME="SCANWCLASS"
2470262685Sdelphij>7.2. scanw() class of functions</A
2471262685Sdelphij></H3
2472262685Sdelphij><P
2473262685Sdelphij>These functions are similar to <TT
2474262685SdelphijCLASS="LITERAL"
2475262685Sdelphij>scanf()</TT
2476262685Sdelphij> with the
2477262685Sdelphijadded capability of getting the input from any location on the screen.</P
2478262685Sdelphij><DIV
2479262685SdelphijCLASS="SECT3"
2480262685Sdelphij><HR><H4
2481262685SdelphijCLASS="SECT3"
2482262685Sdelphij><A
2483262685SdelphijNAME="SCANWMVSCANW"
2484262685Sdelphij>7.2.1. scanw() and mvscanw</A
2485262685Sdelphij></H4
2486262685Sdelphij><P
2487262685Sdelphij>The usage of these functions is similar to that of
2488262685Sdelphij<TT
2489262685SdelphijCLASS="LITERAL"
2490262685Sdelphij>sscanf()</TT
2491262685Sdelphij>, where the line to be scanned is
2492262685Sdelphijprovided by <TT
2493262685SdelphijCLASS="LITERAL"
2494262685Sdelphij>wgetstr()</TT
2495262685Sdelphij> function. That is, these
2496262685Sdelphijfunctions call to <TT
2497262685SdelphijCLASS="LITERAL"
2498262685Sdelphij>wgetstr()</TT
2499262685Sdelphij> function(explained
2500262685Sdelphijbelow) and uses the resulting line for a scan. </P
2501262685Sdelphij></DIV
2502262685Sdelphij><DIV
2503262685SdelphijCLASS="SECT3"
2504262685Sdelphij><HR><H4
2505262685SdelphijCLASS="SECT3"
2506262685Sdelphij><A
2507262685SdelphijNAME="WSCANWMVWSCANW"
2508262685Sdelphij>7.2.2. wscanw() and mvwscanw()</A
2509262685Sdelphij></H4
2510262685Sdelphij><P
2511262685Sdelphij>These are similar to above two functions except that they read from a window,
2512262685Sdelphijwhich is supplied as one of the arguments to these functions. </P
2513262685Sdelphij></DIV
2514262685Sdelphij><DIV
2515262685SdelphijCLASS="SECT3"
2516262685Sdelphij><HR><H4
2517262685SdelphijCLASS="SECT3"
2518262685Sdelphij><A
2519262685SdelphijNAME="VWSCANW"
2520262685Sdelphij>7.2.3. vwscanw()</A
2521262685Sdelphij></H4
2522262685Sdelphij><P
2523262685Sdelphij>This function is similar to <TT
2524262685SdelphijCLASS="LITERAL"
2525262685Sdelphij>vscanf()</TT
2526262685Sdelphij>. This can
2527262685Sdelphijbe used when a variable number of arguments are to be scanned.</P
2528262685Sdelphij></DIV
2529262685Sdelphij></DIV
2530262685Sdelphij><DIV
2531262685SdelphijCLASS="SECT2"
2532262685Sdelphij><HR><H3
2533262685SdelphijCLASS="SECT2"
2534262685Sdelphij><A
2535262685SdelphijNAME="GETSTRCLASS"
2536262685Sdelphij>7.3. getstr() class of functions</A
2537262685Sdelphij></H3
2538262685Sdelphij><P
2539262685Sdelphij>These functions are used to get strings from the terminal. In essence, this
2540262685Sdelphijfunction performs the same task as would be achieved by a series of calls to
2541262685Sdelphij<TT
2542262685SdelphijCLASS="LITERAL"
2543262685Sdelphij>getch()</TT
2544262685Sdelphij> until a newline, carriage return, or
2545262685Sdelphijend-of-file is received. The resulting string of characters are pointed to by
2546262685Sdelphij<TT
2547262685SdelphijCLASS="LITERAL"
2548262685Sdelphij>str</TT
2549262685Sdelphij>, which is a character pointer provided by
2550262685Sdelphijthe user.</P
2551262685Sdelphij></DIV
2552262685Sdelphij><DIV
2553262685SdelphijCLASS="SECT2"
2554262685Sdelphij><HR><H3
2555262685SdelphijCLASS="SECT2"
2556262685Sdelphij><A
2557262685SdelphijNAME="GETSTREX"
2558262685Sdelphij>7.4. Some examples</A
2559262685Sdelphij></H3
2560262685Sdelphij><DIV
2561262685SdelphijCLASS="EXAMPLE"
2562262685Sdelphij><A
2563262685SdelphijNAME="BSCEX"
2564262685Sdelphij></A
2565262685Sdelphij><P
2566262685Sdelphij><B
2567262685Sdelphij>Example 4.  A Simple scanw example </B
2568262685Sdelphij></P
2569262685Sdelphij><PRE
2570262685SdelphijCLASS="PROGRAMLISTING"
2571262685Sdelphij><SPAN
2572262685SdelphijCLASS="INLINEMEDIAOBJECT"
2573262685Sdelphij>#include &#60;ncurses.h&#62;			/* ncurses.h includes stdio.h */  
2574262685Sdelphij#include &#60;string.h&#62; 
2575166124Srafan 
2576166124Srafanint main()
2577166124Srafan{
2578262685Sdelphij char mesg[]="Enter a string: ";		/* message to be appeared on the screen */
2579166124Srafan char str[80];
2580262685Sdelphij int row,col;				/* to store the number of rows and *
2581262685Sdelphij					 * the number of colums of the screen */
2582262685Sdelphij initscr();				/* start the curses mode */
2583262685Sdelphij getmaxyx(stdscr,row,col);		/* get the number of rows and columns */
2584166124Srafan mvprintw(row/2,(col-strlen(mesg))/2,"%s",mesg);
2585262685Sdelphij                     		/* print the message at the center of the screen */
2586166124Srafan getstr(str);
2587166124Srafan mvprintw(LINES - 2, 0, "You Entered: %s", str);
2588166124Srafan getch();
2589166124Srafan endwin();
2590166124Srafan
2591166124Srafan return 0;
2592262685Sdelphij}</SPAN
2593262685Sdelphij></PRE
2594262685Sdelphij></DIV
2595262685Sdelphij></DIV
2596262685Sdelphij></DIV
2597262685Sdelphij><DIV
2598262685SdelphijCLASS="SECT1"
2599262685Sdelphij><HR><H2
2600262685SdelphijCLASS="SECT1"
2601262685Sdelphij><A
2602262685SdelphijNAME="ATTRIB"
2603262685Sdelphij>8. Attributes</A
2604262685Sdelphij></H2
2605262685Sdelphij><P
2606262685Sdelphij>We have seen an example of how attributes can be used to print characters with
2607262685Sdelphijsome special effects. Attributes, when set prudently, can present information in
2608262685Sdelphijan easy, understandable manner. The following program takes a C file as input
2609262685Sdelphijand prints the file with comments in bold. Scan through the code. </P
2610262685Sdelphij><DIV
2611262685SdelphijCLASS="EXAMPLE"
2612262685Sdelphij><A
2613262685SdelphijNAME="BSIAT"
2614262685Sdelphij></A
2615262685Sdelphij><P
2616262685Sdelphij><B
2617262685Sdelphij>Example 5.  A Simple Attributes example </B
2618262685Sdelphij></P
2619262685Sdelphij><PRE
2620262685SdelphijCLASS="PROGRAMLISTING"
2621262685Sdelphij><SPAN
2622262685SdelphijCLASS="INLINEMEDIAOBJECT"
2623262685Sdelphij>/* pager functionality by Joseph Spainhour" &#60;spainhou@bellsouth.net&#62; */
2624262685Sdelphij#include &#60;ncurses.h&#62;
2625262685Sdelphij#include &#60;stdlib.h&#62;
2626166124Srafan
2627166124Srafanint main(int argc, char *argv[])
2628166124Srafan{ 
2629166124Srafan  int ch, prev, row, col;
2630166124Srafan  prev = EOF;
2631166124Srafan  FILE *fp;
2632166124Srafan  int y, x;
2633166124Srafan
2634166124Srafan  if(argc != 2)
2635166124Srafan  {
2636262685Sdelphij    printf("Usage: %s &#60;a c file name&#62;\n", argv[0]);
2637166124Srafan    exit(1);
2638166124Srafan  }
2639166124Srafan  fp = fopen(argv[1], "r");
2640166124Srafan  if(fp == NULL)
2641166124Srafan  {
2642166124Srafan    perror("Cannot open input file");
2643166124Srafan    exit(1);
2644166124Srafan  }
2645262685Sdelphij  initscr();				/* Start curses mode */
2646262685Sdelphij  getmaxyx(stdscr, row, col);		/* find the boundaries of the screeen */
2647262685Sdelphij  while((ch = fgetc(fp)) != EOF)	/* read the file till we reach the end */
2648166124Srafan  {
2649262685Sdelphij    getyx(stdscr, y, x);		/* get the current curser position */
2650262685Sdelphij    if(y == (row - 1))			/* are we are at the end of the screen */
2651166124Srafan    {
2652262685Sdelphij      printw("&#60;-Press Any Key-&#62;");	/* tell the user to press a key */
2653166124Srafan      getch();
2654262685Sdelphij      clear();				/* clear the screen */
2655262685Sdelphij      move(0, 0);			/* start at the beginning of the screen */
2656166124Srafan    }
2657262685Sdelphij    if(prev == '/' &#38;&#38; ch == '*')    	/* If it is / and * then only
2658262685Sdelphij                                     	 * switch bold on */    
2659166124Srafan    {
2660262685Sdelphij      attron(A_BOLD);			/* cut bold on */
2661262685Sdelphij      getyx(stdscr, y, x);		/* get the current curser position */
2662262685Sdelphij      move(y, x - 1);			/* back up one space */
2663262685Sdelphij      printw("%c%c", '/', ch); 		/* The actual printing is done here */
2664166124Srafan    }
2665166124Srafan    else
2666166124Srafan      printw("%c", ch);
2667166124Srafan    refresh();
2668262685Sdelphij    if(prev == '*' &#38;&#38; ch == '/')
2669262685Sdelphij      attroff(A_BOLD);        		/* Switch it off once we got *
2670262685Sdelphij                                 	 * and then / */
2671166124Srafan    prev = ch;
2672166124Srafan  }
2673262685Sdelphij  endwin();                       	/* End curses mode */
2674166124Srafan  fclose(fp);
2675166124Srafan  return 0;
2676262685Sdelphij}</SPAN
2677262685Sdelphij></PRE
2678262685Sdelphij></DIV
2679262685Sdelphij><P
2680262685Sdelphij> 
2681262685SdelphijDon't worry about all those initialization and other crap. Concentrate on 
2682262685Sdelphijthe while loop. It reads each character in the file and searches for the 
2683262685Sdelphijpattern /*. Once it spots the pattern, it switches the BOLD attribute on with 
2684262685Sdelphij<TT
2685262685SdelphijCLASS="LITERAL"
2686262685Sdelphij> attron()</TT
2687262685Sdelphij> . When we get the pattern */ it is 
2688262685Sdelphijswitched off by <TT
2689262685SdelphijCLASS="LITERAL"
2690262685Sdelphij> attroff()</TT
2691262685Sdelphij> .</P
2692262685Sdelphij><P
2693262685Sdelphij> 
2694262685SdelphijThe above program also introduces us to two useful functions
2695262685Sdelphij<TT
2696262685SdelphijCLASS="LITERAL"
2697262685Sdelphij>getyx() </TT
2698262685Sdelphij> and
2699262685Sdelphij<TT
2700262685SdelphijCLASS="LITERAL"
2701262685Sdelphij>move()</TT
2702262685Sdelphij>. The first function gets the
2703262685Sdelphijco-ordinates of the present cursor into the variables y, x. Since getyx() is a
2704166124Srafanmacro we don't have to pass pointers to variables. The function
2705262685Sdelphij<TT
2706262685SdelphijCLASS="LITERAL"
2707262685Sdelphij>move()</TT
2708262685Sdelphij> moves the cursor to the co-ordinates
2709262685Sdelphijgiven to it. </P
2710262685Sdelphij><P
2711262685Sdelphij> 
2712262685SdelphijThe above program is really a simple one which doesn't do much. On these lines
2713262685Sdelphijone could write a more useful program which reads a C file, parses it and prints
2714262685Sdelphijit in different colors. One could even extend it to other languages as well.</P
2715262685Sdelphij><DIV
2716262685SdelphijCLASS="SECT2"
2717262685Sdelphij><HR><H3
2718262685SdelphijCLASS="SECT2"
2719262685Sdelphij><A
2720262685SdelphijNAME="ATTRIBDETAILS"
2721262685Sdelphij>8.1. The details</A
2722262685Sdelphij></H3
2723262685Sdelphij><P
2724262685Sdelphij>Let's get into more details of attributes. The functions <TT
2725262685SdelphijCLASS="LITERAL"
2726262685Sdelphij>attron(), attroff(), attrset() </TT
2727262685Sdelphij>, and their sister functions
2728262685Sdelphij<TT
2729262685SdelphijCLASS="LITERAL"
2730262685Sdelphij> attr_get()</TT
2731262685Sdelphij> etc..  can be used to switch
2732262685Sdelphijattributes on/off , get attributes and produce a colorful display.</P
2733262685Sdelphij><P
2734262685Sdelphij>The functions attron and attroff take a bit-mask of attributes and switch them 
2735262685Sdelphijon or off, respectively. The following video attributes, which are defined in 
2736262685Sdelphij&lt;curses.h&gt; can be passed to these functions. </P
2737262685Sdelphij><PRE
2738262685SdelphijCLASS="PROGRAMLISTING"
2739262685Sdelphij>    
2740166124Srafan    A_NORMAL        Normal display (no highlight)
2741166124Srafan    A_STANDOUT      Best highlighting mode of the terminal.
2742166124Srafan    A_UNDERLINE     Underlining
2743166124Srafan    A_REVERSE       Reverse video
2744166124Srafan    A_BLINK         Blinking
2745166124Srafan    A_DIM           Half bright
2746166124Srafan    A_BOLD          Extra bright or bold
2747166124Srafan    A_PROTECT       Protected mode
2748166124Srafan    A_INVIS         Invisible or blank mode
2749166124Srafan    A_ALTCHARSET    Alternate character set
2750166124Srafan    A_CHARTEXT      Bit-mask to extract a character
2751166124Srafan    COLOR_PAIR(n)   Color-pair number n 
2752262685Sdelphij    </PRE
2753262685Sdelphij><P
2754262685Sdelphij> 
2755262685SdelphijThe last one is the most colorful one :-) Colors are explained in the 
2756262685Sdelphij<A
2757262685SdelphijHREF="#color"
2758262685SdelphijTARGET="_top"
2759262685Sdelphij>next sections</A
2760262685Sdelphij>.</P
2761262685Sdelphij><P
2762262685Sdelphij>We can OR(|) any number of above attributes to get a combined effect. If you 
2763262685Sdelphijwanted reverse video with blinking characters you can use</P
2764262685Sdelphij><PRE
2765262685SdelphijCLASS="PROGRAMLISTING"
2766262685Sdelphij>    attron(A_REVERSE | A_BLINK);</PRE
2767262685Sdelphij></DIV
2768262685Sdelphij><DIV
2769262685SdelphijCLASS="SECT2"
2770262685Sdelphij><HR><H3
2771262685SdelphijCLASS="SECT2"
2772262685Sdelphij><A
2773262685SdelphijNAME="ATTRONVSATTRSET"
2774262685Sdelphij>8.2. attron() vs attrset()</A
2775262685Sdelphij></H3
2776262685Sdelphij><P
2777262685Sdelphij>Then what is the difference between attron() and attrset()? attrset sets the
2778262685Sdelphijattributes of window whereas attron just switches on the attribute given to it.
2779262685SdelphijSo attrset() fully overrides whatever attributes the window previously had and
2780262685Sdelphijsets it to the new attribute(s). Similarly attroff() just switches off the
2781262685Sdelphijattribute(s) given to it as an argument. This gives us the flexibility of
2782262685Sdelphijmanaging attributes easily.But if you use them carelessly you may loose track of
2783262685Sdelphijwhat attributes the window has and garble the display. This is especially true
2784262685Sdelphijwhile managing menus with colors and highlighting. So decide on a consistent
2785262685Sdelphijpolicy and stick to it. You can always use <TT
2786262685SdelphijCLASS="LITERAL"
2787262685Sdelphij> standend()</TT
2788262685Sdelphij> which is equivalent to <TT
2789262685SdelphijCLASS="LITERAL"
2790262685Sdelphij> attrset(A_NORMAL)</TT
2791262685Sdelphij> which turns off all attributes and brings you to normal mode.</P
2792262685Sdelphij></DIV
2793262685Sdelphij><DIV
2794262685SdelphijCLASS="SECT2"
2795262685Sdelphij><HR><H3
2796262685SdelphijCLASS="SECT2"
2797262685Sdelphij><A
2798262685SdelphijNAME="ATTR_GET"
2799262685Sdelphij>8.3. attr_get()</A
2800262685Sdelphij></H3
2801262685Sdelphij><P
2802262685Sdelphij>&#13;The function attr_get() gets the current attributes and color pair of the
2803262685Sdelphijwindow. Though we might not use this as often as the above functions, this is
2804262685Sdelphijuseful in scanning areas of screen. Say we wanted to do some complex update on
2805262685Sdelphijscreen and we are not sure what attribute each character is associated with.
2806262685SdelphijThen this function can be used with either attrset or attron to produce the
2807262685Sdelphijdesired effect.&#13;</P
2808262685Sdelphij></DIV
2809262685Sdelphij><DIV
2810262685SdelphijCLASS="SECT2"
2811262685Sdelphij><HR><H3
2812262685SdelphijCLASS="SECT2"
2813262685Sdelphij><A
2814262685SdelphijNAME="ATTR_FUNCS"
2815262685Sdelphij>8.4. attr_ functions</A
2816262685Sdelphij></H3
2817262685Sdelphij><P
2818262685Sdelphij>There are series of functions like attr_set(), attr_on etc.. These are similar
2819262685Sdelphijto above functions except that they take parameters of type
2820262685Sdelphij<TT
2821262685SdelphijCLASS="LITERAL"
2822262685Sdelphij>attr_t</TT
2823262685Sdelphij>.</P
2824262685Sdelphij></DIV
2825262685Sdelphij><DIV
2826262685SdelphijCLASS="SECT2"
2827262685Sdelphij><HR><H3
2828262685SdelphijCLASS="SECT2"
2829262685Sdelphij><A
2830262685SdelphijNAME="WATTRFUNCS"
2831262685Sdelphij>8.5. wattr functions</A
2832262685Sdelphij></H3
2833262685Sdelphij><P
2834262685Sdelphij>For each of the above functions we have a corresponding function with 'w' which
2835262685Sdelphijoperates on a particular window. The above functions operate on stdscr. </P
2836262685Sdelphij></DIV
2837262685Sdelphij><DIV
2838262685SdelphijCLASS="SECT2"
2839262685Sdelphij><HR><H3
2840262685SdelphijCLASS="SECT2"
2841262685Sdelphij><A
2842262685SdelphijNAME="CHGAT"
2843262685Sdelphij>8.6. chgat() functions</A
2844262685Sdelphij></H3
2845262685Sdelphij><P
2846262685Sdelphij>The function chgat() is listed in the end of the man page curs_attr. It actually
2847262685Sdelphijis a useful one. This function can be used to set attributes for a group of
2848262685Sdelphijcharacters without moving. I mean it !!! without moving the cursor :-) It
2849262685Sdelphijchanges the attributes of a given number of characters starting at the current
2850262685Sdelphijcursor location.</P
2851262685Sdelphij><P
2852262685Sdelphij>We can give -1 as the character count to update till end of line. If you want to
2853262685Sdelphijchange attributes of characters from current position to end of line, just use
2854262685Sdelphijthis.</P
2855262685Sdelphij><PRE
2856262685SdelphijCLASS="PROGRAMLISTING"
2857262685Sdelphij>    chgat(-1, A_REVERSE, 0, NULL);</PRE
2858262685Sdelphij><P
2859262685Sdelphij> 
2860262685SdelphijThis function is useful when changing attributes for characters that are
2861262685Sdelphijalready on the screen. Move to the character from which you want to change and
2862262685Sdelphijchange the attribute. </P
2863262685Sdelphij><P
2864262685Sdelphij>Other functions wchgat(), mvchgat(), wchgat() behave similarly except that the w
2865262685Sdelphijfunctions operate on the particular window. The mv functions first move the
2866262685Sdelphijcursor then perform the work given to them. Actually chgat is a macro which is
2867262685Sdelphijreplaced by a wchgat() with stdscr as the window. Most of the "w-less" functions
2868262685Sdelphijare macros.</P
2869262685Sdelphij><DIV
2870262685SdelphijCLASS="EXAMPLE"
2871262685Sdelphij><A
2872262685SdelphijNAME="BWICH"
2873262685Sdelphij></A
2874262685Sdelphij><P
2875262685Sdelphij><B
2876262685Sdelphij>Example 6.  Chgat() Usage example </B
2877262685Sdelphij></P
2878262685Sdelphij><PRE
2879262685SdelphijCLASS="PROGRAMLISTING"
2880262685Sdelphij><SPAN
2881262685SdelphijCLASS="INLINEMEDIAOBJECT"
2882262685Sdelphij>#include &#60;ncurses.h&#62;
2883166124Srafan
2884166124Srafanint main(int argc, char *argv[])
2885262685Sdelphij{	initscr();			/* Start curses mode 		*/
2886262685Sdelphij	start_color();			/* Start color functionality	*/
2887262685Sdelphij	
2888262685Sdelphij	init_pair(1, COLOR_CYAN, COLOR_BLACK);
2889262685Sdelphij	printw("A Big string which i didn't care to type fully ");
2890262685Sdelphij	mvchgat(0, 0, -1, A_BLINK, 1, NULL);	
2891262685Sdelphij	/* 
2892262685Sdelphij	 * First two parameters specify the position at which to start 
2893262685Sdelphij	 * Third parameter number of characters to update. -1 means till 
2894262685Sdelphij	 * end of line
2895262685Sdelphij	 * Forth parameter is the normal attribute you wanted to give 
2896262685Sdelphij	 * to the charcter
2897262685Sdelphij	 * Fifth is the color index. It is the index given during init_pair()
2898262685Sdelphij	 * use 0 if you didn't want color
2899262685Sdelphij	 * Sixth one is always NULL 
2900262685Sdelphij	 */
2901262685Sdelphij	refresh();
2902262685Sdelphij    	getch();
2903262685Sdelphij	endwin();			/* End curses mode		  */
2904262685Sdelphij	return 0;
2905262685Sdelphij}</SPAN
2906262685Sdelphij></PRE
2907262685Sdelphij></DIV
2908262685Sdelphij><P
2909262685Sdelphij>This example also introduces us to the color world of curses. Colors will be 
2910262685Sdelphijexplained in detail later. Use 0 for no color.</P
2911262685Sdelphij></DIV
2912262685Sdelphij></DIV
2913262685Sdelphij><DIV
2914262685SdelphijCLASS="SECT1"
2915262685Sdelphij><HR><H2
2916262685SdelphijCLASS="SECT1"
2917262685Sdelphij><A
2918262685SdelphijNAME="WINDOWS"
2919262685Sdelphij>9. Windows</A
2920262685Sdelphij></H2
2921262685Sdelphij><P
2922262685Sdelphij>Windows form the most important concept in curses. You have seen the standard
2923262685Sdelphijwindow stdscr above where all the functions implicitly operated on this window.
2924262685SdelphijNow to make design even a simplest GUI, you need to resort to windows.  The main
2925262685Sdelphijreason you may want to use windows is to manipulate parts of the screen
2926262685Sdelphijseparately, for better efficiency, by updating only the windows that need to be
2927262685Sdelphijchanged and for a better design. I would say the last reason is the most
2928262685Sdelphijimportant in going for windows. You should always strive for a better and
2929262685Sdelphijeasy-to-manage design in your programs. If you are writing big, complex GUIs
2930262685Sdelphijthis is of pivotal importance before you start doing anything.</P
2931262685Sdelphij><DIV
2932262685SdelphijCLASS="SECT2"
2933262685Sdelphij><HR><H3
2934262685SdelphijCLASS="SECT2"
2935262685Sdelphij><A
2936262685SdelphijNAME="WINDOWBASICS"
2937262685Sdelphij>9.1. The basics</A
2938262685Sdelphij></H3
2939262685Sdelphij><P
2940262685Sdelphij>A Window can be created by calling the function
2941262685Sdelphij<TT
2942262685SdelphijCLASS="LITERAL"
2943262685Sdelphij>newwin()</TT
2944262685Sdelphij>. It doesn't create any thing on the
2945262685Sdelphijscreen actually. It allocates memory for a structure to manipulate the window
2946262685Sdelphijand updates the structure with data regarding the window like it's size, beginy,
2947262685Sdelphijbeginx etc.. Hence in curses, a window is just an abstraction of an imaginary
2948262685Sdelphijwindow, which can be manipulated independent of other parts of screen. The
2949262685Sdelphijfunction newwin() returns a pointer to structure WINDOW, which can be passed to
2950262685Sdelphijwindow related functions like wprintw() etc.. Finally the window can be
2951262685Sdelphijdestroyed with delwin(). It will deallocate the memory associated with the
2952262685Sdelphijwindow structure.</P
2953262685Sdelphij></DIV
2954262685Sdelphij><DIV
2955262685SdelphijCLASS="SECT2"
2956262685Sdelphij><HR><H3
2957262685SdelphijCLASS="SECT2"
2958262685Sdelphij><A
2959262685SdelphijNAME="LETBEWINDOW"
2960262685Sdelphij>9.2. Let there be a Window !!!</A
2961262685Sdelphij></H3
2962262685Sdelphij><P
2963262685Sdelphij>What fun is it, if a window is created and we can't see it. So the fun part
2964262685Sdelphijbegins by displaying the window. The function
2965262685Sdelphij<TT
2966262685SdelphijCLASS="LITERAL"
2967262685Sdelphij>box()</TT
2968262685Sdelphij> can be used to draw a border around the
2969262685Sdelphijwindow. Let's explore these functions in more detail in this example.</P
2970262685Sdelphij><DIV
2971262685SdelphijCLASS="EXAMPLE"
2972262685Sdelphij><A
2973262685SdelphijNAME="BWIBO"
2974262685Sdelphij></A
2975262685Sdelphij><P
2976262685Sdelphij><B
2977262685Sdelphij>Example 7. Window Border example </B
2978262685Sdelphij></P
2979262685Sdelphij><PRE
2980262685SdelphijCLASS="PROGRAMLISTING"
2981262685Sdelphij><SPAN
2982262685SdelphijCLASS="INLINEMEDIAOBJECT"
2983262685Sdelphij>#include &#60;ncurses.h&#62;
2984166124Srafan
2985166124Srafan
2986166124SrafanWINDOW *create_newwin(int height, int width, int starty, int startx);
2987166124Srafanvoid destroy_win(WINDOW *local_win);
2988166124Srafan
2989166124Srafanint main(int argc, char *argv[])
2990262685Sdelphij{	WINDOW *my_win;
2991262685Sdelphij	int startx, starty, width, height;
2992262685Sdelphij	int ch;
2993166124Srafan
2994262685Sdelphij	initscr();			/* Start curses mode 		*/
2995262685Sdelphij	cbreak();			/* Line buffering disabled, Pass on
2996262685Sdelphij					 * everty thing to me 		*/
2997262685Sdelphij	keypad(stdscr, TRUE);		/* I need that nifty F1 	*/
2998166124Srafan
2999262685Sdelphij	height = 3;
3000262685Sdelphij	width = 10;
3001262685Sdelphij	starty = (LINES - height) / 2;	/* Calculating for a center placement */
3002262685Sdelphij	startx = (COLS - width) / 2;	/* of the window		*/
3003262685Sdelphij	printw("Press F1 to exit");
3004262685Sdelphij	refresh();
3005262685Sdelphij	my_win = create_newwin(height, width, starty, startx);
3006166124Srafan
3007262685Sdelphij	while((ch = getch()) != KEY_F(1))
3008262685Sdelphij	{	switch(ch)
3009262685Sdelphij		{	case KEY_LEFT:
3010262685Sdelphij				destroy_win(my_win);
3011262685Sdelphij				my_win = create_newwin(height, width, starty,--startx);
3012262685Sdelphij				break;
3013262685Sdelphij			case KEY_RIGHT:
3014262685Sdelphij				destroy_win(my_win);
3015262685Sdelphij				my_win = create_newwin(height, width, starty,++startx);
3016262685Sdelphij				break;
3017262685Sdelphij			case KEY_UP:
3018262685Sdelphij				destroy_win(my_win);
3019262685Sdelphij				my_win = create_newwin(height, width, --starty,startx);
3020262685Sdelphij				break;
3021262685Sdelphij			case KEY_DOWN:
3022262685Sdelphij				destroy_win(my_win);
3023262685Sdelphij				my_win = create_newwin(height, width, ++starty,startx);
3024262685Sdelphij				break;	
3025262685Sdelphij		}
3026262685Sdelphij	}
3027262685Sdelphij		
3028262685Sdelphij	endwin();			/* End curses mode		  */
3029262685Sdelphij	return 0;
3030166124Srafan}
3031166124Srafan
3032166124SrafanWINDOW *create_newwin(int height, int width, int starty, int startx)
3033262685Sdelphij{	WINDOW *local_win;
3034166124Srafan
3035262685Sdelphij	local_win = newwin(height, width, starty, startx);
3036262685Sdelphij	box(local_win, 0 , 0);		/* 0, 0 gives default characters 
3037262685Sdelphij					 * for the vertical and horizontal
3038262685Sdelphij					 * lines			*/
3039262685Sdelphij	wrefresh(local_win);		/* Show that box 		*/
3040166124Srafan
3041262685Sdelphij	return local_win;
3042166124Srafan}
3043166124Srafan
3044166124Srafanvoid destroy_win(WINDOW *local_win)
3045262685Sdelphij{	
3046262685Sdelphij	/* box(local_win, ' ', ' '); : This won't produce the desired
3047262685Sdelphij	 * result of erasing the window. It will leave it's four corners 
3048262685Sdelphij	 * and so an ugly remnant of window. 
3049262685Sdelphij	 */
3050262685Sdelphij	wborder(local_win, ' ', ' ', ' ',' ',' ',' ',' ',' ');
3051262685Sdelphij	/* The parameters taken are 
3052262685Sdelphij	 * 1. win: the window on which to operate
3053262685Sdelphij	 * 2. ls: character to be used for the left side of the window 
3054262685Sdelphij	 * 3. rs: character to be used for the right side of the window 
3055262685Sdelphij	 * 4. ts: character to be used for the top side of the window 
3056262685Sdelphij	 * 5. bs: character to be used for the bottom side of the window 
3057262685Sdelphij	 * 6. tl: character to be used for the top left corner of the window 
3058262685Sdelphij	 * 7. tr: character to be used for the top right corner of the window 
3059262685Sdelphij	 * 8. bl: character to be used for the bottom left corner of the window 
3060262685Sdelphij	 * 9. br: character to be used for the bottom right corner of the window
3061262685Sdelphij	 */
3062262685Sdelphij	wrefresh(local_win);
3063262685Sdelphij	delwin(local_win);
3064262685Sdelphij}</SPAN
3065262685Sdelphij></PRE
3066262685Sdelphij></DIV
3067262685Sdelphij></DIV
3068262685Sdelphij><DIV
3069262685SdelphijCLASS="SECT2"
3070262685Sdelphij><HR><H3
3071262685SdelphijCLASS="SECT2"
3072262685Sdelphij><A
3073262685SdelphijNAME="BORDEREXEXPL"
3074262685Sdelphij>9.3. Explanation</A
3075262685Sdelphij></H3
3076262685Sdelphij><P
3077262685Sdelphij>Don't scream. I know it's a big example. But I have to explain some important
3078262685Sdelphijthings here :-). This program creates a rectangular window that can be moved 
3079262685Sdelphijwith left, right, up, down arrow keys. It repeatedly creates and destroys
3080262685Sdelphijwindows as user press a key. Don't go beyond the screen limits. Checking for
3081262685Sdelphijthose limits is left as an exercise for the reader. Let's dissect it by line by line.</P
3082262685Sdelphij><P
3083262685Sdelphij>The <TT
3084262685SdelphijCLASS="LITERAL"
3085262685Sdelphij>create_newwin()</TT
3086262685Sdelphij> function creates a window
3087262685Sdelphijwith <TT
3088262685SdelphijCLASS="LITERAL"
3089262685Sdelphij>newwin() </TT
3090262685Sdelphij> and displays a border around it
3091262685Sdelphijwith box. The function <TT
3092262685SdelphijCLASS="LITERAL"
3093262685Sdelphij> destroy_win()</TT
3094262685Sdelphij> first
3095262685Sdelphijerases the window from screen by painting a border with ' ' character and then
3096262685Sdelphijcalling <TT
3097262685SdelphijCLASS="LITERAL"
3098262685Sdelphij>delwin()</TT
3099262685Sdelphij> to deallocate memory related
3100262685Sdelphijto it. Depending on the key the user presses, starty or startx is changed and a
3101262685Sdelphijnew window is created.</P
3102262685Sdelphij><P
3103262685Sdelphij>In the destroy_win, as you can see, I used wborder instead of box. The reason is
3104262685Sdelphijwritten in the comments (You missed it. I know. Read the code :-)). wborder 
3105262685Sdelphijdraws a border around the window with the characters given to it as the 4 corner
3106262685Sdelphijpoints and the 4 lines. To put it clearly, if you have called wborder as below:
3107262685Sdelphij<PRE
3108262685SdelphijCLASS="PROGRAMLISTING"
3109262685Sdelphij>    wborder(win, '|', '|', '-', '-', '+', '+', '+', '+');</PRE
3110262685Sdelphij></P
3111262685Sdelphij><P
3112262685Sdelphij>it produces some thing like </P
3113262685Sdelphij><PRE
3114262685SdelphijCLASS="PROGRAMLISTING"
3115262685Sdelphij>    +------------+
3116166124Srafan    |            |
3117166124Srafan    |            |
3118166124Srafan    |            |
3119166124Srafan    |            |
3120166124Srafan    |            |
3121166124Srafan    |            |
3122262685Sdelphij    +------------+</PRE
3123262685Sdelphij></DIV
3124262685Sdelphij><DIV
3125262685SdelphijCLASS="SECT2"
3126262685Sdelphij><HR><H3
3127262685SdelphijCLASS="SECT2"
3128262685Sdelphij><A
3129262685SdelphijNAME="OTHERSTUFF"
3130262685Sdelphij>9.4. The other stuff in the example</A
3131262685Sdelphij></H3
3132262685Sdelphij><P
3133262685Sdelphij>You can also see in the above examples, that I have used the variables COLS,
3134262685SdelphijLINES which are initialized to the screen sizes after initscr(). They can be
3135262685Sdelphijuseful in finding screen dimensions and finding the center co-ordinate of the
3136262685Sdelphijscreen as above. The function <TT
3137262685SdelphijCLASS="LITERAL"
3138262685Sdelphij>getch()</TT
3139262685Sdelphij> as usual
3140262685Sdelphijgets the key from keyboard and according to the key it does the corresponding
3141262685Sdelphijwork. This type of switch- case is very common in any GUI based programs.</P
3142262685Sdelphij></DIV
3143262685Sdelphij><DIV
3144262685SdelphijCLASS="SECT2"
3145262685Sdelphij><HR><H3
3146262685SdelphijCLASS="SECT2"
3147262685Sdelphij><A
3148262685SdelphijNAME="OTHERBORDERFUNCS"
3149262685Sdelphij>9.5. Other Border functions</A
3150262685Sdelphij></H3
3151262685Sdelphij><P
3152262685Sdelphij>Above program is grossly inefficient in that with each press of a key, a window
3153262685Sdelphijis destroyed and another is created. So let's write a more efficient program
3154262685Sdelphijwhich uses other border related functions.</P
3155262685Sdelphij><P
3156262685Sdelphij>The following program uses <TT
3157262685SdelphijCLASS="LITERAL"
3158262685Sdelphij>mvhline()</TT
3159262685Sdelphij> and
3160262685Sdelphij<TT
3161262685SdelphijCLASS="LITERAL"
3162262685Sdelphij>mvvline()</TT
3163262685Sdelphij> to achieve similar effect. These two
3164262685Sdelphijfunctions are simple. They create a horizontal or vertical line of the specified
3165262685Sdelphijlength at the specified position.</P
3166262685Sdelphij><DIV
3167262685SdelphijCLASS="EXAMPLE"
3168262685Sdelphij><A
3169262685SdelphijNAME="BOTBO"
3170262685Sdelphij></A
3171262685Sdelphij><P
3172262685Sdelphij><B
3173262685Sdelphij>Example 8.  More border functions</B
3174262685Sdelphij></P
3175262685Sdelphij><PRE
3176262685SdelphijCLASS="PROGRAMLISTING"
3177262685Sdelphij><SPAN
3178262685SdelphijCLASS="INLINEMEDIAOBJECT"
3179262685Sdelphij>#include &#60;ncurses.h&#62;
3180166124Srafan
3181166124Srafantypedef struct _win_border_struct {
3182262685Sdelphij	chtype 	ls, rs, ts, bs, 
3183262685Sdelphij	 	tl, tr, bl, br;
3184166124Srafan}WIN_BORDER;
3185166124Srafan
3186166124Srafantypedef struct _WIN_struct {
3187166124Srafan
3188262685Sdelphij	int startx, starty;
3189262685Sdelphij	int height, width;
3190262685Sdelphij	WIN_BORDER border;
3191166124Srafan}WIN;
3192166124Srafan
3193166124Srafanvoid init_win_params(WIN *p_win);
3194166124Srafanvoid print_win_params(WIN *p_win);
3195166124Srafanvoid create_box(WIN *win, bool flag);
3196166124Srafan
3197166124Srafanint main(int argc, char *argv[])
3198262685Sdelphij{	WIN win;
3199262685Sdelphij	int ch;
3200166124Srafan
3201262685Sdelphij	initscr();			/* Start curses mode 		*/
3202262685Sdelphij	start_color();			/* Start the color functionality */
3203262685Sdelphij	cbreak();			/* Line buffering disabled, Pass on
3204262685Sdelphij					 * everty thing to me 		*/
3205262685Sdelphij	keypad(stdscr, TRUE);		/* I need that nifty F1 	*/
3206262685Sdelphij	noecho();
3207262685Sdelphij	init_pair(1, COLOR_CYAN, COLOR_BLACK);
3208166124Srafan
3209262685Sdelphij	/* Initialize the window parameters */
3210262685Sdelphij	init_win_params(&#38;win);
3211262685Sdelphij	print_win_params(&#38;win);
3212166124Srafan
3213262685Sdelphij	attron(COLOR_PAIR(1));
3214262685Sdelphij	printw("Press F1 to exit");
3215262685Sdelphij	refresh();
3216262685Sdelphij	attroff(COLOR_PAIR(1));
3217262685Sdelphij	
3218262685Sdelphij	create_box(&#38;win, TRUE);
3219262685Sdelphij	while((ch = getch()) != KEY_F(1))
3220262685Sdelphij	{	switch(ch)
3221262685Sdelphij		{	case KEY_LEFT:
3222262685Sdelphij				create_box(&#38;win, FALSE);
3223262685Sdelphij				--win.startx;
3224262685Sdelphij				create_box(&#38;win, TRUE);
3225262685Sdelphij				break;
3226262685Sdelphij			case KEY_RIGHT:
3227262685Sdelphij				create_box(&#38;win, FALSE);
3228262685Sdelphij				++win.startx;
3229262685Sdelphij				create_box(&#38;win, TRUE);
3230262685Sdelphij				break;
3231262685Sdelphij			case KEY_UP:
3232262685Sdelphij				create_box(&#38;win, FALSE);
3233262685Sdelphij				--win.starty;
3234262685Sdelphij				create_box(&#38;win, TRUE);
3235262685Sdelphij				break;
3236262685Sdelphij			case KEY_DOWN:
3237262685Sdelphij				create_box(&#38;win, FALSE);
3238262685Sdelphij				++win.starty;
3239262685Sdelphij				create_box(&#38;win, TRUE);
3240262685Sdelphij				break;	
3241262685Sdelphij		}
3242262685Sdelphij	}
3243262685Sdelphij	endwin();			/* End curses mode		  */
3244262685Sdelphij	return 0;
3245166124Srafan}
3246166124Srafanvoid init_win_params(WIN *p_win)
3247166124Srafan{
3248262685Sdelphij	p_win-&#62;height = 3;
3249262685Sdelphij	p_win-&#62;width = 10;
3250262685Sdelphij	p_win-&#62;starty = (LINES - p_win-&#62;height)/2;	
3251262685Sdelphij	p_win-&#62;startx = (COLS - p_win-&#62;width)/2;
3252166124Srafan
3253262685Sdelphij	p_win-&#62;border.ls = '|';
3254262685Sdelphij	p_win-&#62;border.rs = '|';
3255262685Sdelphij	p_win-&#62;border.ts = '-';
3256262685Sdelphij	p_win-&#62;border.bs = '-';
3257262685Sdelphij	p_win-&#62;border.tl = '+';
3258262685Sdelphij	p_win-&#62;border.tr = '+';
3259262685Sdelphij	p_win-&#62;border.bl = '+';
3260262685Sdelphij	p_win-&#62;border.br = '+';
3261166124Srafan
3262166124Srafan}
3263166124Srafanvoid print_win_params(WIN *p_win)
3264166124Srafan{
3265166124Srafan#ifdef _DEBUG
3266262685Sdelphij	mvprintw(25, 0, "%d %d %d %d", p_win-&#62;startx, p_win-&#62;starty, 
3267262685Sdelphij				p_win-&#62;width, p_win-&#62;height);
3268262685Sdelphij	refresh();
3269166124Srafan#endif
3270166124Srafan}
3271166124Srafanvoid create_box(WIN *p_win, bool flag)
3272262685Sdelphij{	int i, j;
3273262685Sdelphij	int x, y, w, h;
3274166124Srafan
3275262685Sdelphij	x = p_win-&#62;startx;
3276262685Sdelphij	y = p_win-&#62;starty;
3277262685Sdelphij	w = p_win-&#62;width;
3278262685Sdelphij	h = p_win-&#62;height;
3279166124Srafan
3280262685Sdelphij	if(flag == TRUE)
3281262685Sdelphij	{	mvaddch(y, x, p_win-&#62;border.tl);
3282262685Sdelphij		mvaddch(y, x + w, p_win-&#62;border.tr);
3283262685Sdelphij		mvaddch(y + h, x, p_win-&#62;border.bl);
3284262685Sdelphij		mvaddch(y + h, x + w, p_win-&#62;border.br);
3285262685Sdelphij		mvhline(y, x + 1, p_win-&#62;border.ts, w - 1);
3286262685Sdelphij		mvhline(y + h, x + 1, p_win-&#62;border.bs, w - 1);
3287262685Sdelphij		mvvline(y + 1, x, p_win-&#62;border.ls, h - 1);
3288262685Sdelphij		mvvline(y + 1, x + w, p_win-&#62;border.rs, h - 1);
3289166124Srafan
3290262685Sdelphij	}
3291262685Sdelphij	else
3292262685Sdelphij		for(j = y; j &#60;= y + h; ++j)
3293262685Sdelphij			for(i = x; i &#60;= x + w; ++i)
3294262685Sdelphij				mvaddch(j, i, ' ');
3295262685Sdelphij				
3296262685Sdelphij	refresh();
3297166124Srafan
3298262685Sdelphij}</SPAN
3299262685Sdelphij></PRE
3300262685Sdelphij></DIV
3301262685Sdelphij></DIV
3302262685Sdelphij></DIV
3303262685Sdelphij><DIV
3304262685SdelphijCLASS="SECT1"
3305262685Sdelphij><HR><H2
3306262685SdelphijCLASS="SECT1"
3307262685Sdelphij><A
3308262685SdelphijNAME="COLOR"
3309262685Sdelphij>10. Colors</A
3310262685Sdelphij></H2
3311262685Sdelphij><DIV
3312262685SdelphijCLASS="SECT2"
3313262685Sdelphij><H3
3314262685SdelphijCLASS="SECT2"
3315262685Sdelphij><A
3316262685SdelphijNAME="COLORBASICS"
3317262685Sdelphij>10.1. The basics</A
3318262685Sdelphij></H3
3319262685Sdelphij><P
3320262685Sdelphij>Life seems dull with no colors. Curses has a nice mechanism to handle colors.
3321262685SdelphijLet's get into the thick of the things with a small program.</P
3322262685Sdelphij><DIV
3323262685SdelphijCLASS="EXAMPLE"
3324262685Sdelphij><A
3325262685SdelphijNAME="BSICO"
3326262685Sdelphij></A
3327262685Sdelphij><P
3328262685Sdelphij><B
3329262685Sdelphij>Example 9.  A Simple Color example </B
3330262685Sdelphij></P
3331262685Sdelphij><PRE
3332262685SdelphijCLASS="PROGRAMLISTING"
3333262685Sdelphij><SPAN
3334262685SdelphijCLASS="INLINEMEDIAOBJECT"
3335262685Sdelphij>#include &#60;ncurses.h&#62;
3336166124Srafan
3337166124Srafanvoid print_in_middle(WINDOW *win, int starty, int startx, int width, char *string);
3338166124Srafanint main(int argc, char *argv[])
3339262685Sdelphij{	initscr();			/* Start curses mode 		*/
3340262685Sdelphij	if(has_colors() == FALSE)
3341262685Sdelphij	{	endwin();
3342262685Sdelphij		printf("Your terminal does not support color\n");
3343262685Sdelphij		exit(1);
3344262685Sdelphij	}
3345262685Sdelphij	start_color();			/* Start color 			*/
3346262685Sdelphij	init_pair(1, COLOR_RED, COLOR_BLACK);
3347166124Srafan
3348262685Sdelphij	attron(COLOR_PAIR(1));
3349262685Sdelphij	print_in_middle(stdscr, LINES / 2, 0, 0, "Viola !!! In color ...");
3350262685Sdelphij	attroff(COLOR_PAIR(1));
3351262685Sdelphij    	getch();
3352262685Sdelphij	endwin();
3353166124Srafan}
3354166124Srafanvoid print_in_middle(WINDOW *win, int starty, int startx, int width, char *string)
3355262685Sdelphij{	int length, x, y;
3356262685Sdelphij	float temp;
3357166124Srafan
3358262685Sdelphij	if(win == NULL)
3359262685Sdelphij		win = stdscr;
3360262685Sdelphij	getyx(win, y, x);
3361262685Sdelphij	if(startx != 0)
3362262685Sdelphij		x = startx;
3363262685Sdelphij	if(starty != 0)
3364262685Sdelphij		y = starty;
3365262685Sdelphij	if(width == 0)
3366262685Sdelphij		width = 80;
3367166124Srafan
3368262685Sdelphij	length = strlen(string);
3369262685Sdelphij	temp = (width - length)/ 2;
3370262685Sdelphij	x = startx + (int)temp;
3371262685Sdelphij	mvwprintw(win, y, x, "%s", string);
3372262685Sdelphij	refresh();
3373166124Srafan}
3374262685Sdelphij</SPAN
3375262685Sdelphij></PRE
3376262685Sdelphij></DIV
3377262685Sdelphij><P
3378262685Sdelphij>As you can see, to start using color, you should first call the function
3379262685Sdelphij<TT
3380262685SdelphijCLASS="LITERAL"
3381262685Sdelphij> start_color()</TT
3382262685Sdelphij>. After that, you can use color
3383262685Sdelphijcapabilities of your terminals using various functions. To find out whether a
3384262685Sdelphijterminal has color capabilities or not, you can use
3385262685Sdelphij<TT
3386262685SdelphijCLASS="LITERAL"
3387262685Sdelphij>has_colors()</TT
3388262685Sdelphij> function, which returns FALSE if
3389262685Sdelphijthe terminal does not support color. </P
3390262685Sdelphij><P
3391262685Sdelphij>Curses initializes all the colors supported by terminal when start_color() is
3392262685Sdelphijcalled. These can be accessed by the define constants like
3393262685Sdelphij<TT
3394262685SdelphijCLASS="LITERAL"
3395262685Sdelphij>COLOR_BLACK </TT
3396262685Sdelphij> etc. Now to actually start using
3397262685Sdelphijcolors, you have to define pairs. Colors are always used in pairs. That means
3398262685Sdelphijyou have to use the function <TT
3399262685SdelphijCLASS="LITERAL"
3400262685Sdelphij>init_pair() </TT
3401262685Sdelphij> to
3402262685Sdelphijdefine the foreground and background for the pair number you give.  After that
3403262685Sdelphijthat pair number can be used as a normal attribute with <TT
3404262685SdelphijCLASS="LITERAL"
3405262685Sdelphij>COLOR_PAIR()</TT
3406262685Sdelphij>function. This may seem to be cumbersome at first.
3407262685SdelphijBut this elegant solution allows us to manage color pairs very easily. To
3408262685Sdelphijappreciate it, you have to look into the the source code of "dialog", a utility
3409262685Sdelphijfor displaying dialog boxes from shell scripts. The developers have defined
3410262685Sdelphijforeground and background combinations for all the colors they might need and
3411262685Sdelphijinitialized at the beginning. This makes it very easy to set attributes just by
3412262685Sdelphijaccessing a pair which we already have defined as a constant.</P
3413262685Sdelphij><P
3414262685Sdelphij>The following colors are defined in <TT
3415262685SdelphijCLASS="LITERAL"
3416262685Sdelphij>curses.h</TT
3417262685Sdelphij>.
3418262685SdelphijYou can use these as parameters for various color functions.
3419262685Sdelphij<PRE
3420262685SdelphijCLASS="PROGRAMLISTING"
3421262685Sdelphij>        COLOR_BLACK   0
3422166124Srafan        COLOR_RED     1
3423166124Srafan        COLOR_GREEN   2
3424166124Srafan        COLOR_YELLOW  3
3425166124Srafan        COLOR_BLUE    4
3426166124Srafan        COLOR_MAGENTA 5
3427166124Srafan        COLOR_CYAN    6
3428262685Sdelphij        COLOR_WHITE   7</PRE
3429262685Sdelphij></P
3430262685Sdelphij></DIV
3431262685Sdelphij><DIV
3432262685SdelphijCLASS="SECT2"
3433262685Sdelphij><HR><H3
3434262685SdelphijCLASS="SECT2"
3435262685Sdelphij><A
3436262685SdelphijNAME="CHANGECOLORDEFS"
3437262685Sdelphij>10.2. Changing Color Definitions</A
3438262685Sdelphij></H3
3439262685Sdelphij><P
3440262685Sdelphij>The function <TT
3441262685SdelphijCLASS="LITERAL"
3442262685Sdelphij>init_color()</TT
3443262685Sdelphij>can be used to change
3444262685Sdelphijthe rgb values for the colors defined by curses initially. Say you wanted to
3445262685Sdelphijlighten the intensity of red color by a minuscule. Then you can use this
3446262685Sdelphijfunction as</P
3447262685Sdelphij><PRE
3448262685SdelphijCLASS="PROGRAMLISTING"
3449262685Sdelphij>    init_color(COLOR_RED, 700, 0, 0);
3450166124Srafan    /* param 1     : color name
3451262685Sdelphij     * param 2, 3, 4 : rgb content min = 0, max = 1000 */</PRE
3452262685Sdelphij><P
3453262685Sdelphij>If your terminal cannot change the color definitions, the function returns ERR.
3454262685SdelphijThe function <TT
3455262685SdelphijCLASS="LITERAL"
3456262685Sdelphij>can_change_color()</TT
3457262685Sdelphij> can be used to
3458262685Sdelphijfind out whether the terminal has the capability of changing color content or
3459262685Sdelphijnot.  The rgb content is scaled from 0 to 1000. Initially RED color is defined
3460262685Sdelphijwith content 1000(r), 0(g), 0(b). </P
3461262685Sdelphij></DIV
3462262685Sdelphij><DIV
3463262685SdelphijCLASS="SECT2"
3464262685Sdelphij><HR><H3
3465262685SdelphijCLASS="SECT2"
3466262685Sdelphij><A
3467262685SdelphijNAME="COLORCONTENT"
3468262685Sdelphij>10.3. Color Content</A
3469262685Sdelphij></H3
3470262685Sdelphij><P
3471262685Sdelphij>The functions <TT
3472262685SdelphijCLASS="LITERAL"
3473262685Sdelphij>color_content()</TT
3474262685Sdelphij> and
3475262685Sdelphij<TT
3476262685SdelphijCLASS="LITERAL"
3477262685Sdelphij>pair_content()</TT
3478262685Sdelphij> can be used to find the color
3479262685Sdelphijcontent and foreground, background combination for the pair. </P
3480262685Sdelphij></DIV
3481262685Sdelphij></DIV
3482262685Sdelphij><DIV
3483262685SdelphijCLASS="SECT1"
3484262685Sdelphij><HR><H2
3485262685SdelphijCLASS="SECT1"
3486262685Sdelphij><A
3487262685SdelphijNAME="KEYS"
3488262685Sdelphij>11. Interfacing with the key board</A
3489262685Sdelphij></H2
3490262685Sdelphij><DIV
3491262685SdelphijCLASS="SECT2"
3492262685Sdelphij><H3
3493262685SdelphijCLASS="SECT2"
3494262685Sdelphij><A
3495262685SdelphijNAME="KEYSBASICS"
3496262685Sdelphij>11.1. The Basics</A
3497262685Sdelphij></H3
3498262685Sdelphij><P
3499262685Sdelphij>No GUI is complete without a strong user interface and to interact with the
3500262685Sdelphijuser, a curses program should be sensitive to key presses or the mouse actions
3501262685Sdelphijdone by the user. Let's deal with the keys first.</P
3502262685Sdelphij><P
3503262685Sdelphij>As you have seen in almost all of the above examples, it's very easy to get key
3504262685Sdelphijinput from the user. A simple way of getting key presses is to use
3505262685Sdelphij<TT
3506262685SdelphijCLASS="LITERAL"
3507262685Sdelphij>getch()</TT
3508262685Sdelphij> function. The cbreak mode should be
3509262685Sdelphijenabled to read keys when you are interested in reading individual key hits
3510262685Sdelphijrather than complete lines of text (which usually end with a carriage return).
3511262685Sdelphijkeypad should be enabled to get the Functions keys, arrow keys etc.  See the
3512262685Sdelphijinitialization section for details.</P
3513262685Sdelphij><P
3514262685Sdelphij><TT
3515262685SdelphijCLASS="LITERAL"
3516262685Sdelphij>getch()</TT
3517262685Sdelphij> returns an integer corresponding to the
3518262685Sdelphijkey pressed. If it is a normal character, the integer value will be equivalent
3519262685Sdelphijto the character. Otherwise it returns a number which can be matched with the
3520262685Sdelphijconstants defined in <TT
3521262685SdelphijCLASS="LITERAL"
3522262685Sdelphij>curses.h</TT
3523262685Sdelphij>.  For example if
3524262685Sdelphijthe user presses F1, the integer returned is 265. This can be checked using the
3525262685Sdelphijmacro KEY_F() defined in curses.h. This makes reading keys portable and easy to
3526262685Sdelphijmanage.</P
3527262685Sdelphij><P
3528262685Sdelphij>For example, if you call getch() like this</P
3529262685Sdelphij><PRE
3530262685SdelphijCLASS="PROGRAMLISTING"
3531262685Sdelphij>    int ch;
3532166124Srafan
3533262685Sdelphij    ch = getch();</PRE
3534262685Sdelphij><P
3535262685Sdelphij>getch() will wait for the user to press a key, (unless you specified a timeout)
3536262685Sdelphijand when user presses a key, the corresponding integer is returned. Then you can
3537262685Sdelphijcheck the value returned with the constants defined in curses.h to match against
3538262685Sdelphijthe keys you want.</P
3539262685Sdelphij><P
3540262685Sdelphij>The following code piece will do that job.</P
3541262685Sdelphij><PRE
3542262685SdelphijCLASS="PROGRAMLISTING"
3543262685Sdelphij>    if(ch == KEY_LEFT)
3544262685Sdelphij        printw("Left arrow is pressed\n");</PRE
3545262685Sdelphij><P
3546262685Sdelphij>Let's write a small program which creates a menu which can be navigated by up
3547262685Sdelphijand down arrows.</P
3548262685Sdelphij></DIV
3549262685Sdelphij><DIV
3550262685SdelphijCLASS="SECT2"
3551262685Sdelphij><HR><H3
3552262685SdelphijCLASS="SECT2"
3553262685Sdelphij><A
3554262685SdelphijNAME="SIMPLEKEYEX"
3555262685Sdelphij>11.2. A Simple Key Usage example</A
3556262685Sdelphij></H3
3557262685Sdelphij><DIV
3558262685SdelphijCLASS="EXAMPLE"
3559262685Sdelphij><A
3560262685SdelphijNAME="BSIKE"
3561262685Sdelphij></A
3562262685Sdelphij><P
3563262685Sdelphij><B
3564262685Sdelphij>Example 10.  A Simple Key Usage example </B
3565262685Sdelphij></P
3566262685Sdelphij><PRE
3567262685SdelphijCLASS="PROGRAMLISTING"
3568262685Sdelphij><SPAN
3569262685SdelphijCLASS="INLINEMEDIAOBJECT"
3570262685Sdelphij>#include &#60;stdio.h&#62;
3571262685Sdelphij#include &#60;ncurses.h&#62;
3572166124Srafan
3573166124Srafan#define WIDTH 30
3574166124Srafan#define HEIGHT 10 
3575166124Srafan
3576166124Srafanint startx = 0;
3577166124Srafanint starty = 0;
3578166124Srafan
3579166124Srafanchar *choices[] = { 
3580262685Sdelphij			"Choice 1",
3581262685Sdelphij			"Choice 2",
3582262685Sdelphij			"Choice 3",
3583262685Sdelphij			"Choice 4",
3584262685Sdelphij			"Exit",
3585262685Sdelphij		  };
3586166124Srafanint n_choices = sizeof(choices) / sizeof(char *);
3587166124Srafanvoid print_menu(WINDOW *menu_win, int highlight);
3588166124Srafan
3589166124Srafanint main()
3590262685Sdelphij{	WINDOW *menu_win;
3591262685Sdelphij	int highlight = 1;
3592262685Sdelphij	int choice = 0;
3593262685Sdelphij	int c;
3594166124Srafan
3595262685Sdelphij	initscr();
3596262685Sdelphij	clear();
3597262685Sdelphij	noecho();
3598262685Sdelphij	cbreak();	/* Line buffering disabled. pass on everything */
3599262685Sdelphij	startx = (80 - WIDTH) / 2;
3600262685Sdelphij	starty = (24 - HEIGHT) / 2;
3601262685Sdelphij		
3602262685Sdelphij	menu_win = newwin(HEIGHT, WIDTH, starty, startx);
3603262685Sdelphij	keypad(menu_win, TRUE);
3604262685Sdelphij	mvprintw(0, 0, "Use arrow keys to go up and down, Press enter to select a choice");
3605262685Sdelphij	refresh();
3606262685Sdelphij	print_menu(menu_win, highlight);
3607262685Sdelphij	while(1)
3608262685Sdelphij	{	c = wgetch(menu_win);
3609262685Sdelphij		switch(c)
3610262685Sdelphij		{	case KEY_UP:
3611262685Sdelphij				if(highlight == 1)
3612262685Sdelphij					highlight = n_choices;
3613262685Sdelphij				else
3614262685Sdelphij					--highlight;
3615262685Sdelphij				break;
3616262685Sdelphij			case KEY_DOWN:
3617262685Sdelphij				if(highlight == n_choices)
3618262685Sdelphij					highlight = 1;
3619262685Sdelphij				else 
3620262685Sdelphij					++highlight;
3621262685Sdelphij				break;
3622262685Sdelphij			case 10:
3623262685Sdelphij				choice = highlight;
3624262685Sdelphij				break;
3625262685Sdelphij			default:
3626262685Sdelphij				mvprintw(24, 0, "Charcter pressed is = %3d Hopefully it can be printed as '%c'", c, c);
3627262685Sdelphij				refresh();
3628262685Sdelphij				break;
3629262685Sdelphij		}
3630262685Sdelphij		print_menu(menu_win, highlight);
3631262685Sdelphij		if(choice != 0)	/* User did a choice come out of the infinite loop */
3632262685Sdelphij			break;
3633262685Sdelphij	}	
3634262685Sdelphij	mvprintw(23, 0, "You chose choice %d with choice string %s\n", choice, choices[choice - 1]);
3635262685Sdelphij	clrtoeol();
3636262685Sdelphij	refresh();
3637262685Sdelphij	endwin();
3638262685Sdelphij	return 0;
3639166124Srafan}
3640166124Srafan
3641166124Srafan
3642166124Srafanvoid print_menu(WINDOW *menu_win, int highlight)
3643166124Srafan{
3644262685Sdelphij	int x, y, i;	
3645166124Srafan
3646262685Sdelphij	x = 2;
3647262685Sdelphij	y = 2;
3648262685Sdelphij	box(menu_win, 0, 0);
3649262685Sdelphij	for(i = 0; i &#60; n_choices; ++i)
3650262685Sdelphij	{	if(highlight == i + 1) /* High light the present choice */
3651262685Sdelphij		{	wattron(menu_win, A_REVERSE); 
3652262685Sdelphij			mvwprintw(menu_win, y, x, "%s", choices[i]);
3653262685Sdelphij			wattroff(menu_win, A_REVERSE);
3654262685Sdelphij		}
3655262685Sdelphij		else
3656262685Sdelphij			mvwprintw(menu_win, y, x, "%s", choices[i]);
3657262685Sdelphij		++y;
3658262685Sdelphij	}
3659262685Sdelphij	wrefresh(menu_win);
3660166124Srafan}
3661262685Sdelphij</SPAN
3662262685Sdelphij></PRE
3663262685Sdelphij></DIV
3664262685Sdelphij></DIV
3665262685Sdelphij></DIV
3666262685Sdelphij><DIV
3667262685SdelphijCLASS="SECT1"
3668262685Sdelphij><HR><H2
3669262685SdelphijCLASS="SECT1"
3670262685Sdelphij><A
3671262685SdelphijNAME="MOUSE"
3672262685Sdelphij>12. Interfacing with the mouse</A
3673262685Sdelphij></H2
3674262685Sdelphij><P
3675262685Sdelphij>Now that you have seen how to get keys, lets do the same thing from mouse.
3676262685SdelphijUsually each UI allows the user to interact with both keyboard and mouse. </P
3677262685Sdelphij><DIV
3678262685SdelphijCLASS="SECT2"
3679262685Sdelphij><HR><H3
3680262685SdelphijCLASS="SECT2"
3681262685Sdelphij><A
3682262685SdelphijNAME="MOUSEBASICS"
3683262685Sdelphij>12.1. The Basics</A
3684262685Sdelphij></H3
3685262685Sdelphij><P
3686262685Sdelphij>Before you do any thing else, the events you want to receive have to be enabled
3687262685Sdelphijwith <TT
3688262685SdelphijCLASS="LITERAL"
3689262685Sdelphij>mousemask()</TT
3690262685Sdelphij>.</P
3691262685Sdelphij><PRE
3692262685SdelphijCLASS="PROGRAMLISTING"
3693262685Sdelphij>    mousemask(  mmask_t newmask,    /* The events you want to listen to */
3694262685Sdelphij                mmask_t *oldmask)    /* The old events mask                */</PRE
3695262685Sdelphij><P
3696262685Sdelphij>The first parameter to above function is a bit mask of events you would like to 
3697262685Sdelphijlisten. By default, all the events are turned off. The bit mask <TT
3698262685SdelphijCLASS="LITERAL"
3699262685Sdelphij> ALL_MOUSE_EVENTS</TT
3700262685Sdelphij> can be used to get all the events.</P
3701262685Sdelphij><P
3702262685Sdelphij>The following are all the event masks:</P
3703262685Sdelphij><PRE
3704262685SdelphijCLASS="PROGRAMLISTING"
3705262685Sdelphij>    Name            Description
3706166124Srafan       ---------------------------------------------------------------------
3707166124Srafan       BUTTON1_PRESSED          mouse button 1 down
3708166124Srafan       BUTTON1_RELEASED         mouse button 1 up
3709166124Srafan       BUTTON1_CLICKED          mouse button 1 clicked
3710166124Srafan       BUTTON1_DOUBLE_CLICKED   mouse button 1 double clicked
3711166124Srafan       BUTTON1_TRIPLE_CLICKED   mouse button 1 triple clicked
3712166124Srafan       BUTTON2_PRESSED          mouse button 2 down
3713166124Srafan       BUTTON2_RELEASED         mouse button 2 up
3714166124Srafan       BUTTON2_CLICKED          mouse button 2 clicked
3715166124Srafan       BUTTON2_DOUBLE_CLICKED   mouse button 2 double clicked
3716166124Srafan       BUTTON2_TRIPLE_CLICKED   mouse button 2 triple clicked
3717166124Srafan       BUTTON3_PRESSED          mouse button 3 down
3718166124Srafan       BUTTON3_RELEASED         mouse button 3 up
3719166124Srafan       BUTTON3_CLICKED          mouse button 3 clicked
3720166124Srafan       BUTTON3_DOUBLE_CLICKED   mouse button 3 double clicked
3721166124Srafan       BUTTON3_TRIPLE_CLICKED   mouse button 3 triple clicked
3722166124Srafan       BUTTON4_PRESSED          mouse button 4 down
3723166124Srafan       BUTTON4_RELEASED         mouse button 4 up
3724166124Srafan       BUTTON4_CLICKED          mouse button 4 clicked
3725166124Srafan       BUTTON4_DOUBLE_CLICKED   mouse button 4 double clicked
3726166124Srafan       BUTTON4_TRIPLE_CLICKED   mouse button 4 triple clicked
3727166124Srafan       BUTTON_SHIFT             shift was down during button state change
3728166124Srafan       BUTTON_CTRL              control was down during button state change
3729166124Srafan       BUTTON_ALT               alt was down during button state change
3730166124Srafan       ALL_MOUSE_EVENTS         report all button state changes
3731262685Sdelphij       REPORT_MOUSE_POSITION    report mouse movement</PRE
3732262685Sdelphij></DIV
3733262685Sdelphij><DIV
3734262685SdelphijCLASS="SECT2"
3735262685Sdelphij><HR><H3
3736262685SdelphijCLASS="SECT2"
3737262685Sdelphij><A
3738262685SdelphijNAME="GETTINGEVENTS"
3739262685Sdelphij>12.2. Getting the events</A
3740262685Sdelphij></H3
3741262685Sdelphij><P
3742262685Sdelphij>Once a class of mouse events have been enabled, getch() class of functions
3743262685Sdelphijreturn KEY_MOUSE every time some mouse event happens. Then the mouse event can
3744262685Sdelphijbe retrieved with <TT
3745262685SdelphijCLASS="LITERAL"
3746262685Sdelphij>getmouse()</TT
3747262685Sdelphij>.</P
3748262685Sdelphij><P
3749262685Sdelphij>The code approximately looks like this:</P
3750262685Sdelphij><PRE
3751262685SdelphijCLASS="PROGRAMLISTING"
3752262685Sdelphij>    MEVENT event;
3753166124Srafan
3754166124Srafan    ch = getch();
3755166124Srafan    if(ch == KEY_MOUSE)
3756166124Srafan        if(getmouse(&amp;event) == OK)
3757166124Srafan            .    /* Do some thing with the event */
3758166124Srafan            .
3759262685Sdelphij            .</PRE
3760262685Sdelphij><P
3761262685Sdelphij> 
3762262685Sdelphijgetmouse() returns the event into the pointer given to it. It's a structure
3763262685Sdelphijwhich contains</P
3764262685Sdelphij><PRE
3765262685SdelphijCLASS="PROGRAMLISTING"
3766262685Sdelphij>    typedef struct
3767166124Srafan    {
3768166124Srafan        short id;         /* ID to distinguish multiple devices */
3769166124Srafan        int x, y, z;      /* event coordinates */
3770166124Srafan        mmask_t bstate;   /* button state bits */
3771262685Sdelphij    }    </PRE
3772262685Sdelphij><P
3773262685Sdelphij>The <TT
3774262685SdelphijCLASS="LITERAL"
3775262685Sdelphij>bstate</TT
3776262685Sdelphij> is the main variable we are
3777262685Sdelphijinterested in. It tells the button state of the mouse.</P
3778262685Sdelphij><P
3779262685Sdelphij>Then with a code snippet like the following, we can find out what happened.</P
3780262685Sdelphij><PRE
3781262685SdelphijCLASS="PROGRAMLISTING"
3782262685Sdelphij>    if(event.bstate &amp; BUTTON1_PRESSED)
3783262685Sdelphij        printw("Left Button Pressed");</PRE
3784262685Sdelphij></DIV
3785262685Sdelphij><DIV
3786262685SdelphijCLASS="SECT2"
3787262685Sdelphij><HR><H3
3788262685SdelphijCLASS="SECT2"
3789262685Sdelphij><A
3790262685SdelphijNAME="MOUSETOGETHER"
3791262685Sdelphij>12.3. Putting it all Together</A
3792262685Sdelphij></H3
3793262685Sdelphij><P
3794262685Sdelphij>That's pretty much interfacing with mouse. Let's create the same menu and enable
3795262685Sdelphijmouse interaction. To make things simpler, key handling is removed.</P
3796262685Sdelphij><DIV
3797262685SdelphijCLASS="EXAMPLE"
3798262685Sdelphij><A
3799262685SdelphijNAME="BMOME"
3800262685Sdelphij></A
3801262685Sdelphij><P
3802262685Sdelphij><B
3803262685Sdelphij>Example 11.  Access the menu with mouse !!! </B
3804262685Sdelphij></P
3805262685Sdelphij><PRE
3806262685SdelphijCLASS="PROGRAMLISTING"
3807262685Sdelphij><SPAN
3808262685SdelphijCLASS="INLINEMEDIAOBJECT"
3809262685Sdelphij>#include &#60;ncurses.h&#62;
3810166124Srafan
3811166124Srafan#define WIDTH 30
3812166124Srafan#define HEIGHT 10 
3813166124Srafan
3814166124Srafanint startx = 0;
3815166124Srafanint starty = 0;
3816166124Srafan
3817262685Sdelphijchar *choices[] = { 	"Choice 1",
3818262685Sdelphij			"Choice 2",
3819262685Sdelphij			"Choice 3",
3820262685Sdelphij			"Choice 4",
3821262685Sdelphij			"Exit",
3822262685Sdelphij		  };
3823166124Srafan
3824166124Srafanint n_choices = sizeof(choices) / sizeof(char *);
3825166124Srafan
3826166124Srafanvoid print_menu(WINDOW *menu_win, int highlight);
3827166124Srafanvoid report_choice(int mouse_x, int mouse_y, int *p_choice);
3828166124Srafan
3829166124Srafanint main()
3830262685Sdelphij{	int c, choice = 0;
3831262685Sdelphij	WINDOW *menu_win;
3832262685Sdelphij	MEVENT event;
3833166124Srafan
3834262685Sdelphij	/* Initialize curses */
3835262685Sdelphij	initscr();
3836262685Sdelphij	clear();
3837262685Sdelphij	noecho();
3838262685Sdelphij	cbreak();	//Line buffering disabled. pass on everything
3839166124Srafan
3840262685Sdelphij	/* Try to put the window in the middle of screen */
3841262685Sdelphij	startx = (80 - WIDTH) / 2;
3842262685Sdelphij	starty = (24 - HEIGHT) / 2;
3843262685Sdelphij	
3844262685Sdelphij	attron(A_REVERSE);
3845262685Sdelphij	mvprintw(23, 1, "Click on Exit to quit (Works best in a virtual console)");
3846262685Sdelphij	refresh();
3847262685Sdelphij	attroff(A_REVERSE);
3848166124Srafan
3849262685Sdelphij	/* Print the menu for the first time */
3850262685Sdelphij	menu_win = newwin(HEIGHT, WIDTH, starty, startx);
3851262685Sdelphij	print_menu(menu_win, 1);
3852262685Sdelphij	/* Get all the mouse events */
3853262685Sdelphij	mousemask(ALL_MOUSE_EVENTS, NULL);
3854262685Sdelphij	
3855262685Sdelphij	while(1)
3856262685Sdelphij	{	c = wgetch(menu_win);
3857262685Sdelphij		switch(c)
3858262685Sdelphij		{	case KEY_MOUSE:
3859262685Sdelphij			if(getmouse(&#38;event) == OK)
3860262685Sdelphij			{	/* When the user clicks left mouse button */
3861262685Sdelphij				if(event.bstate &#38; BUTTON1_PRESSED)
3862262685Sdelphij				{	report_choice(event.x + 1, event.y + 1, &#38;choice);
3863262685Sdelphij					if(choice == -1) //Exit chosen
3864262685Sdelphij						goto end;
3865262685Sdelphij					mvprintw(22, 1, "Choice made is : %d String Chosen is \"%10s\"", choice, choices[choice - 1]);
3866262685Sdelphij					refresh(); 
3867262685Sdelphij				}
3868262685Sdelphij			}
3869262685Sdelphij			print_menu(menu_win, choice);
3870262685Sdelphij			break;
3871262685Sdelphij		}
3872262685Sdelphij	}		
3873166124Srafanend:
3874262685Sdelphij	endwin();
3875262685Sdelphij	return 0;
3876166124Srafan}
3877166124Srafan
3878166124Srafan
3879166124Srafanvoid print_menu(WINDOW *menu_win, int highlight)
3880166124Srafan{
3881262685Sdelphij	int x, y, i;	
3882166124Srafan
3883262685Sdelphij	x = 2;
3884262685Sdelphij	y = 2;
3885262685Sdelphij	box(menu_win, 0, 0);
3886262685Sdelphij	for(i = 0; i &#60; n_choices; ++i)
3887262685Sdelphij	{	if(highlight == i + 1)
3888262685Sdelphij		{	wattron(menu_win, A_REVERSE); 
3889262685Sdelphij			mvwprintw(menu_win, y, x, "%s", choices[i]);
3890262685Sdelphij			wattroff(menu_win, A_REVERSE);
3891262685Sdelphij		}
3892262685Sdelphij		else
3893262685Sdelphij			mvwprintw(menu_win, y, x, "%s", choices[i]);
3894262685Sdelphij		++y;
3895262685Sdelphij	}
3896262685Sdelphij	wrefresh(menu_win);
3897166124Srafan}
3898166124Srafan
3899166124Srafan/* Report the choice according to mouse position */
3900166124Srafanvoid report_choice(int mouse_x, int mouse_y, int *p_choice)
3901262685Sdelphij{	int i,j, choice;
3902166124Srafan
3903262685Sdelphij	i = startx + 2;
3904262685Sdelphij	j = starty + 3;
3905262685Sdelphij	
3906262685Sdelphij	for(choice = 0; choice &#60; n_choices; ++choice)
3907262685Sdelphij		if(mouse_y == j + choice &#38;&#38; mouse_x &#62;= i &#38;&#38; mouse_x &#60;= i + strlen(choices[choice]))
3908262685Sdelphij		{	if(choice == n_choices - 1)
3909262685Sdelphij				*p_choice = -1;		
3910262685Sdelphij			else
3911262685Sdelphij				*p_choice = choice + 1;	
3912262685Sdelphij			break;
3913262685Sdelphij		}
3914262685Sdelphij}</SPAN
3915262685Sdelphij></PRE
3916262685Sdelphij></DIV
3917262685Sdelphij></DIV
3918262685Sdelphij><DIV
3919262685SdelphijCLASS="SECT2"
3920262685Sdelphij><HR><H3
3921262685SdelphijCLASS="SECT2"
3922262685Sdelphij><A
3923262685SdelphijNAME="MISCMOUSEFUNCS"
3924262685Sdelphij>12.4. Miscellaneous Functions</A
3925262685Sdelphij></H3
3926262685Sdelphij><P
3927262685Sdelphij>The functions mouse_trafo() and wmouse_trafo() can be used to convert to mouse
3928262685Sdelphijco-ordinates to screen relative co-ordinates. See curs_mouse(3X) man page for details.</P
3929262685Sdelphij><P
3930262685Sdelphij>The  mouseinterval  function sets the maximum time (in thousands of a
3931262685Sdelphijsecond) that can elapse between press and release events in order for
3932262685Sdelphijthem to be recognized as a click.  This function returns the previous
3933262685Sdelphijinterval value.  The default is one fifth of a second.</P
3934262685Sdelphij></DIV
3935262685Sdelphij></DIV
3936262685Sdelphij><DIV
3937262685SdelphijCLASS="SECT1"
3938262685Sdelphij><HR><H2
3939262685SdelphijCLASS="SECT1"
3940262685Sdelphij><A
3941262685SdelphijNAME="SCREEN"
3942262685Sdelphij>13. Screen Manipulation</A
3943262685Sdelphij></H2
3944262685Sdelphij><P
3945262685Sdelphij>In this section, we will look into some functions, which allow us to manage the
3946262685Sdelphijscreen efficiently and to write some fancy programs. This is especially
3947262685Sdelphijimportant in writing games. </P
3948262685Sdelphij><DIV
3949262685SdelphijCLASS="SECT2"
3950262685Sdelphij><HR><H3
3951262685SdelphijCLASS="SECT2"
3952262685Sdelphij><A
3953262685SdelphijNAME="GETYX"
3954262685Sdelphij>13.1. getyx() functions</A
3955262685Sdelphij></H3
3956262685Sdelphij><P
3957262685Sdelphij>&#13;The function <TT
3958262685SdelphijCLASS="LITERAL"
3959262685Sdelphij>getyx()</TT
3960262685Sdelphij> can be used to find out
3961262685Sdelphijthe present cursor co-ordinates. It will fill the values of x and y co-ordinates
3962262685Sdelphijin the arguments given to it. Since getyx() is a macro you don't have to pass
3963262685Sdelphijthe address of the variables. It can be called as</P
3964262685Sdelphij><PRE
3965262685SdelphijCLASS="PROGRAMLISTING"
3966262685Sdelphij>    getyx(win, y, x);
3967166124Srafan    /* win: window pointer
3968166124Srafan     *   y, x: y, x co-ordinates will be put into this variables 
3969262685Sdelphij     */</PRE
3970262685Sdelphij><P
3971262685Sdelphij>The function getparyx() gets the beginning co-ordinates of the sub window
3972262685Sdelphijrelative to the main window. This is some times useful to update a sub window.
3973262685SdelphijWhen designing fancy stuff like writing multiple menus, it becomes difficult to
3974262685Sdelphijstore the menu positions, their first option co-ordinates etc. A simple solution
3975262685Sdelphijto this problem, is to create menus in sub windows and later find the starting
3976262685Sdelphijco-ordinates of the menus by using getparyx().</P
3977262685Sdelphij><P
3978262685Sdelphij>The functions getbegyx() and getmaxyx() store current window's beginning and
3979262685Sdelphijmaximum co-ordinates. These functions are useful in the same way as above in
3980262685Sdelphijmanaging the windows and sub windows effectively.</P
3981262685Sdelphij></DIV
3982262685Sdelphij><DIV
3983262685SdelphijCLASS="SECT2"
3984262685Sdelphij><HR><H3
3985262685SdelphijCLASS="SECT2"
3986262685Sdelphij><A
3987262685SdelphijNAME="SCREENDUMP"
3988262685Sdelphij>13.2. Screen Dumping</A
3989262685Sdelphij></H3
3990262685Sdelphij><P
3991262685Sdelphij>While writing games, some times it becomes necessary to store the state of the
3992262685Sdelphijscreen and restore it back to the same state. The function scr_dump() can be
3993262685Sdelphijused to dump the screen contents to a file given as an argument. Later it can be
3994262685Sdelphijrestored by scr_restore function. These two simple functions can be used
3995262685Sdelphijeffectively to maintain a fast moving game with changing scenarios. </P
3996262685Sdelphij></DIV
3997262685Sdelphij><DIV
3998262685SdelphijCLASS="SECT2"
3999262685Sdelphij><HR><H3
4000262685SdelphijCLASS="SECT2"
4001262685Sdelphij><A
4002262685SdelphijNAME="WINDOWDUMP"
4003262685Sdelphij>13.3. Window Dumping</A
4004262685Sdelphij></H3
4005262685Sdelphij><P
4006262685Sdelphij>To store and restore windows, the functions
4007262685Sdelphij<TT
4008262685SdelphijCLASS="LITERAL"
4009262685Sdelphij>putwin()</TT
4010262685Sdelphij> and <TT
4011262685SdelphijCLASS="LITERAL"
4012262685Sdelphij>getwin()</TT
4013262685Sdelphij> can be used. <TT
4014262685SdelphijCLASS="LITERAL"
4015262685Sdelphij>putwin()</TT
4016262685Sdelphij> puts
4017262685Sdelphijthe present window state into a file, which can be later restored by
4018262685Sdelphij<TT
4019262685SdelphijCLASS="LITERAL"
4020262685Sdelphij>getwin()</TT
4021262685Sdelphij>.</P
4022262685Sdelphij><P
4023262685Sdelphij> 
4024262685SdelphijThe function <TT
4025262685SdelphijCLASS="LITERAL"
4026262685Sdelphij>copywin()</TT
4027262685Sdelphij> can be used to copy a
4028262685Sdelphijwindow completely onto another window. It takes the source and destination
4029262685Sdelphijwindows as parameters and according to the rectangle specified, it copies the
4030262685Sdelphijrectangular region from source to destination window.  It's last parameter
4031262685Sdelphijspecifies whether to overwrite or just overlay the contents on to the
4032262685Sdelphijdestination window. If this argument is true, then the copying is
4033262685Sdelphijnon-destructive.</P
4034262685Sdelphij></DIV
4035262685Sdelphij></DIV
4036262685Sdelphij><DIV
4037262685SdelphijCLASS="SECT1"
4038262685Sdelphij><HR><H2
4039262685SdelphijCLASS="SECT1"
4040262685Sdelphij><A
4041262685SdelphijNAME="MISC"
4042262685Sdelphij>14. Miscellaneous features</A
4043262685Sdelphij></H2
4044262685Sdelphij><P
4045262685Sdelphij>Now you know enough features to write a good curses program, with all bells and
4046262685Sdelphijwhistles. There are some miscellaneous functions which are useful in various
4047262685Sdelphijcases.  Let's go headlong into some of those.</P
4048262685Sdelphij><DIV
4049262685SdelphijCLASS="SECT2"
4050262685Sdelphij><HR><H3
4051262685SdelphijCLASS="SECT2"
4052262685Sdelphij><A
4053262685SdelphijNAME="CURSSET"
4054262685Sdelphij>14.1. curs_set()</A
4055262685Sdelphij></H3
4056262685Sdelphij><P
4057262685Sdelphij>This function can be used to make the cursor invisible. The parameter to this
4058262685Sdelphijfunction should be </P
4059262685Sdelphij><PRE
4060262685SdelphijCLASS="PROGRAMLISTING"
4061262685Sdelphij>    0 : invisible      or
4062166124Srafan    1 : normal    or
4063262685Sdelphij    2 : very visible.</PRE
4064262685Sdelphij></DIV
4065262685Sdelphij><DIV
4066262685SdelphijCLASS="SECT2"
4067262685Sdelphij><HR><H3
4068262685SdelphijCLASS="SECT2"
4069262685Sdelphij><A
4070262685SdelphijNAME="TEMPLEAVE"
4071262685Sdelphij>14.2. Temporarily Leaving Curses mode</A
4072262685Sdelphij></H3
4073262685Sdelphij><P
4074262685Sdelphij>Some times you may want to get back to cooked mode (normal line buffering mode)
4075262685Sdelphijtemporarily. In such a case you will first need to save the tty modes with a
4076262685Sdelphijcall to <TT
4077262685SdelphijCLASS="LITERAL"
4078262685Sdelphij>def_prog_mode()</TT
4079262685Sdelphij> and then call
4080262685Sdelphij<TT
4081262685SdelphijCLASS="LITERAL"
4082262685Sdelphij>endwin()</TT
4083262685Sdelphij> to end the curses mode. This will
4084262685Sdelphijleave you in the original tty mode. To get back to curses once you are done,
4085262685Sdelphijcall <TT
4086262685SdelphijCLASS="LITERAL"
4087262685Sdelphij>reset_prog_mode() </TT
4088262685Sdelphij>. This function returns
4089262685Sdelphijthe tty to the state stored by <TT
4090262685SdelphijCLASS="LITERAL"
4091262685Sdelphij>def_prog_mode()</TT
4092262685Sdelphij>. Then do refresh(), and you are back to the curses mode. Here
4093262685Sdelphijis an example showing the sequence of things to be done.</P
4094262685Sdelphij><DIV
4095262685SdelphijCLASS="EXAMPLE"
4096262685Sdelphij><A
4097262685SdelphijNAME="BTELE"
4098262685Sdelphij></A
4099262685Sdelphij><P
4100262685Sdelphij><B
4101262685Sdelphij>Example 12.  Temporarily Leaving Curses Mode </B
4102262685Sdelphij></P
4103262685Sdelphij><PRE
4104262685SdelphijCLASS="PROGRAMLISTING"
4105262685Sdelphij><SPAN
4106262685SdelphijCLASS="INLINEMEDIAOBJECT"
4107262685Sdelphij>#include &#60;ncurses.h&#62;
4108166124Srafan
4109166124Srafanint main()
4110262685Sdelphij{	
4111262685Sdelphij	initscr();			/* Start curses mode 		  */
4112262685Sdelphij	printw("Hello World !!!\n");	/* Print Hello World		  */
4113262685Sdelphij	refresh();			/* Print it on to the real screen */
4114262685Sdelphij	def_prog_mode();		/* Save the tty modes		  */
4115262685Sdelphij	endwin();			/* End curses mode temporarily	  */
4116262685Sdelphij	system("/bin/sh");		/* Do whatever you like in cooked mode */
4117262685Sdelphij	reset_prog_mode();		/* Return to the previous tty mode*/
4118262685Sdelphij					/* stored by def_prog_mode() 	  */
4119262685Sdelphij	refresh();			/* Do refresh() to restore the	  */
4120262685Sdelphij					/* Screen contents		  */
4121262685Sdelphij	printw("Another String\n");	/* Back to curses use the full    */
4122262685Sdelphij	refresh();			/* capabilities of curses	  */
4123262685Sdelphij	endwin();			/* End curses mode		  */
4124166124Srafan
4125262685Sdelphij	return 0;
4126262685Sdelphij}</SPAN
4127262685Sdelphij></PRE
4128262685Sdelphij></DIV
4129262685Sdelphij></DIV
4130262685Sdelphij><DIV
4131262685SdelphijCLASS="SECT2"
4132262685Sdelphij><HR><H3
4133262685SdelphijCLASS="SECT2"
4134262685Sdelphij><A
4135262685SdelphijNAME="ACSVARS"
4136262685Sdelphij>14.3. ACS_ variables</A
4137262685Sdelphij></H3
4138262685Sdelphij><P
4139262685Sdelphij>If you have ever programmed in DOS, you know about those nifty characters in
4140262685Sdelphijextended character set. They are printable only on some terminals. NCURSES 
4141262685Sdelphijfunctions like <TT
4142262685SdelphijCLASS="LITERAL"
4143262685Sdelphij>box()</TT
4144262685Sdelphij> use these characters. All
4145262685Sdelphijthese variables start with ACS meaning alternative character set. You might have 
4146262685Sdelphijnoticed me using these characters in some of the programs above. Here's an example 
4147262685Sdelphijshowing all the characters.</P
4148262685Sdelphij><DIV
4149262685SdelphijCLASS="EXAMPLE"
4150262685Sdelphij><A
4151262685SdelphijNAME="BACSVARS"
4152262685Sdelphij></A
4153262685Sdelphij><P
4154262685Sdelphij><B
4155262685Sdelphij>Example 13.  ACS Variables Example </B
4156262685Sdelphij></P
4157262685Sdelphij><PRE
4158262685SdelphijCLASS="PROGRAMLISTING"
4159262685Sdelphij><SPAN
4160262685SdelphijCLASS="INLINEMEDIAOBJECT"
4161262685Sdelphij>#include &#60;ncurses.h&#62;
4162166124Srafan
4163166124Srafanint main()
4164166124Srafan{
4165166124Srafan        initscr();
4166166124Srafan
4167166124Srafan        printw("Upper left corner           "); addch(ACS_ULCORNER); printw("\n"); 
4168166124Srafan        printw("Lower left corner           "); addch(ACS_LLCORNER); printw("\n");
4169166124Srafan        printw("Lower right corner          "); addch(ACS_LRCORNER); printw("\n");
4170166124Srafan        printw("Tee pointing right          "); addch(ACS_LTEE); printw("\n");
4171166124Srafan        printw("Tee pointing left           "); addch(ACS_RTEE); printw("\n");
4172166124Srafan        printw("Tee pointing up             "); addch(ACS_BTEE); printw("\n");
4173166124Srafan        printw("Tee pointing down           "); addch(ACS_TTEE); printw("\n");
4174166124Srafan        printw("Horizontal line             "); addch(ACS_HLINE); printw("\n");
4175166124Srafan        printw("Vertical line               "); addch(ACS_VLINE); printw("\n");
4176166124Srafan        printw("Large Plus or cross over    "); addch(ACS_PLUS); printw("\n");
4177166124Srafan        printw("Scan Line 1                 "); addch(ACS_S1); printw("\n");
4178166124Srafan        printw("Scan Line 3                 "); addch(ACS_S3); printw("\n");
4179166124Srafan        printw("Scan Line 7                 "); addch(ACS_S7); printw("\n");
4180166124Srafan        printw("Scan Line 9                 "); addch(ACS_S9); printw("\n");
4181166124Srafan        printw("Diamond                     "); addch(ACS_DIAMOND); printw("\n");
4182166124Srafan        printw("Checker board (stipple)     "); addch(ACS_CKBOARD); printw("\n");
4183166124Srafan        printw("Degree Symbol               "); addch(ACS_DEGREE); printw("\n");
4184166124Srafan        printw("Plus/Minus Symbol           "); addch(ACS_PLMINUS); printw("\n");
4185166124Srafan        printw("Bullet                      "); addch(ACS_BULLET); printw("\n");
4186166124Srafan        printw("Arrow Pointing Left         "); addch(ACS_LARROW); printw("\n");
4187166124Srafan        printw("Arrow Pointing Right        "); addch(ACS_RARROW); printw("\n");
4188166124Srafan        printw("Arrow Pointing Down         "); addch(ACS_DARROW); printw("\n");
4189166124Srafan        printw("Arrow Pointing Up           "); addch(ACS_UARROW); printw("\n");
4190166124Srafan        printw("Board of squares            "); addch(ACS_BOARD); printw("\n");
4191166124Srafan        printw("Lantern Symbol              "); addch(ACS_LANTERN); printw("\n");
4192166124Srafan        printw("Solid Square Block          "); addch(ACS_BLOCK); printw("\n");
4193166124Srafan        printw("Less/Equal sign             "); addch(ACS_LEQUAL); printw("\n");
4194166124Srafan        printw("Greater/Equal sign          "); addch(ACS_GEQUAL); printw("\n");
4195166124Srafan        printw("Pi                          "); addch(ACS_PI); printw("\n");
4196166124Srafan        printw("Not equal                   "); addch(ACS_NEQUAL); printw("\n");
4197166124Srafan        printw("UK pound sign               "); addch(ACS_STERLING); printw("\n");
4198166124Srafan
4199166124Srafan        refresh();
4200166124Srafan        getch();
4201166124Srafan        endwin();
4202166124Srafan
4203262685Sdelphij	return 0;
4204262685Sdelphij}</SPAN
4205262685Sdelphij></PRE
4206262685Sdelphij></DIV
4207262685Sdelphij></DIV
4208262685Sdelphij></DIV
4209262685Sdelphij><DIV
4210262685SdelphijCLASS="SECT1"
4211262685Sdelphij><HR><H2
4212262685SdelphijCLASS="SECT1"
4213262685Sdelphij><A
4214262685SdelphijNAME="OTHERLIB"
4215262685Sdelphij>15. Other libraries</A
4216262685Sdelphij></H2
4217262685Sdelphij><P
4218262685Sdelphij>Apart from the curses library, there are few text mode libraries, which provide
4219262685Sdelphijmore functionality and a lot of features. The following sections explain three 
4220262685Sdelphijstandard libraries which are usually distributed along with curses. </P
4221262685Sdelphij></DIV
4222262685Sdelphij><DIV
4223262685SdelphijCLASS="SECT1"
4224262685Sdelphij><HR><H2
4225262685SdelphijCLASS="SECT1"
4226262685Sdelphij><A
4227262685SdelphijNAME="PANELS"
4228262685Sdelphij>16. Panel Library</A
4229262685Sdelphij></H2
4230262685Sdelphij><P
4231262685Sdelphij>Now that you are proficient in curses, you wanted to do some thing big. You
4232262685Sdelphijcreated a lot of overlapping windows to give a professional windows-type look.
4233262685SdelphijUnfortunately, it soon becomes difficult to manage these. The multiple
4234262685Sdelphijrefreshes, updates plunge you into a nightmare. The overlapping windows create
4235262685Sdelphijblotches, whenever you forget to refresh the windows in the proper order. </P
4236262685Sdelphij><P
4237262685Sdelphij>Don't despair. There's an elegant solution provided in panels library. In the
4238262685Sdelphijwords of developers of ncurses </P
4239262685Sdelphij><P
4240262685Sdelphij><SPAN
4241262685SdelphijCLASS="emphasis"
4242262685Sdelphij><I
4243262685SdelphijCLASS="EMPHASIS"
4244262685Sdelphij>When your interface design is such that windows may dive deeper into the
4245262685Sdelphijvisibility stack or pop to the top at runtime, the resulting book-keeping can be
4246262685Sdelphijtedious and difficult to get right. Hence the panels library.</I
4247262685Sdelphij></SPAN
4248262685Sdelphij></P
4249262685Sdelphij><P
4250262685Sdelphij>If you have lot of overlapping windows, then panels library is the way to go. It
4251262685Sdelphijobviates the need of doing series of wnoutrefresh(), doupdate() and relieves the
4252262685Sdelphijburden of doing it correctly(bottom up). The library maintains information about
4253262685Sdelphijthe order of windows, their overlapping and update the screen properly. So why
4254262685Sdelphijwait? Let's take a close peek into panels.</P
4255262685Sdelphij><DIV
4256262685SdelphijCLASS="SECT2"
4257262685Sdelphij><HR><H3
4258262685SdelphijCLASS="SECT2"
4259262685Sdelphij><A
4260262685SdelphijNAME="PANELBASICS"
4261262685Sdelphij>16.1. The Basics</A
4262262685Sdelphij></H3
4263262685Sdelphij><P
4264262685Sdelphij>Panel object is a window that is implicitly treated as part of a deck including
4265262685Sdelphijall other panel objects. The deck is treated as a stack with the top panel being
4266262685Sdelphijcompletely visible and the other panels may or may not be obscured according to
4267262685Sdelphijtheir positions. So the basic idea is to create a stack of overlapping panels
4268262685Sdelphijand use panels library to display them correctly. There is a function similar to
4269262685Sdelphijrefresh() which, when called , displays panels in the correct order. Functions
4270262685Sdelphijare provided to hide or show panels, move panels, change its size etc.. The
4271262685Sdelphijoverlapping problem is managed by the panels library during all the calls to
4272262685Sdelphijthese functions. </P
4273262685Sdelphij><P
4274262685Sdelphij>The general flow of a panel program goes like this:
4275262685Sdelphij
4276262685Sdelphij<P
4277262685Sdelphij></P
4278262685Sdelphij><OL
4279262685SdelphijTYPE="1"
4280262685Sdelphij><LI
4281262685Sdelphij><P
4282262685Sdelphij>Create the windows (with newwin()) to be attached to the panels.</P
4283262685Sdelphij></LI
4284262685Sdelphij><LI
4285262685Sdelphij><P
4286262685Sdelphij>Create panels with the chosen visibility order. Stack them up according to the 
4287262685Sdelphijdesired visibility. The function new_panel() is used to created panels.</P
4288262685Sdelphij></LI
4289262685Sdelphij><LI
4290262685Sdelphij><P
4291262685Sdelphij>Call update_panels() to write the panels to the virtual screen in correct
4292262685Sdelphijvisibility order. Do a doupdate() to show it on the screen. </P
4293262685Sdelphij></LI
4294262685Sdelphij><LI
4295262685Sdelphij><P
4296262685Sdelphij>Mainpulate the panels with show_panel(), hide_panel(), move_panel() etc. Make
4297262685Sdelphijuse of helper functions like panel_hidden() and panel_window(). Make use of user
4298262685Sdelphijpointer to store custom data for a panel. Use the functions set_panel_userptr()
4299262685Sdelphijand panel_userptr() to set and get the user pointer for a panel.</P
4300262685Sdelphij></LI
4301262685Sdelphij><LI
4302262685Sdelphij><P
4303262685Sdelphij>When you are done with the panel use del_panel() to delete the panel.</P
4304262685Sdelphij></LI
4305262685Sdelphij></OL
4306262685Sdelphij></P
4307262685Sdelphij><P
4308262685Sdelphij>Let's make the concepts clear, with some programs.  The following is a simple
4309262685Sdelphijprogram which creates 3 overlapping panels and shows them on the screen. </P
4310262685Sdelphij></DIV
4311262685Sdelphij><DIV
4312262685SdelphijCLASS="SECT2"
4313262685Sdelphij><HR><H3
4314262685SdelphijCLASS="SECT2"
4315262685Sdelphij><A
4316262685SdelphijNAME="COMPILEPANELS"
4317262685Sdelphij>16.2. Compiling With the Panels Library</A
4318262685Sdelphij></H3
4319262685Sdelphij><P
4320262685Sdelphij>To use panels library functions, you have to include panel.h and to link the
4321262685Sdelphijprogram with panels library the flag -lpanel should be added along with
4322262685Sdelphij-lncurses in that order.</P
4323262685Sdelphij><PRE
4324262685SdelphijCLASS="PROGRAMLISTING"
4325262685Sdelphij>    #include &lt;panel.h&gt;
4326166124Srafan    .
4327166124Srafan    .
4328166124Srafan    .
4329166124Srafan
4330262685Sdelphij    compile and link: gcc &lt;program file&gt; -lpanel -lncurses</PRE
4331262685Sdelphij><DIV
4332262685SdelphijCLASS="EXAMPLE"
4333262685Sdelphij><A
4334262685SdelphijNAME="PPASI"
4335262685Sdelphij></A
4336262685Sdelphij><P
4337262685Sdelphij><B
4338262685Sdelphij>Example 14.  Panel basics</B
4339262685Sdelphij></P
4340262685Sdelphij><PRE
4341262685SdelphijCLASS="PROGRAMLISTING"
4342262685Sdelphij><SPAN
4343262685SdelphijCLASS="INLINEMEDIAOBJECT"
4344262685Sdelphij>#include &#60;panel.h&#62;
4345166124Srafan
4346166124Srafanint main()
4347262685Sdelphij{	WINDOW *my_wins[3];
4348262685Sdelphij	PANEL  *my_panels[3];
4349262685Sdelphij	int lines = 10, cols = 40, y = 2, x = 4, i;
4350166124Srafan
4351262685Sdelphij	initscr();
4352262685Sdelphij	cbreak();
4353262685Sdelphij	noecho();
4354166124Srafan
4355262685Sdelphij	/* Create windows for the panels */
4356262685Sdelphij	my_wins[0] = newwin(lines, cols, y, x);
4357262685Sdelphij	my_wins[1] = newwin(lines, cols, y + 1, x + 5);
4358262685Sdelphij	my_wins[2] = newwin(lines, cols, y + 2, x + 10);
4359166124Srafan
4360262685Sdelphij	/* 
4361262685Sdelphij	 * Create borders around the windows so that you can see the effect
4362262685Sdelphij	 * of panels
4363262685Sdelphij	 */
4364262685Sdelphij	for(i = 0; i &#60; 3; ++i)
4365262685Sdelphij		box(my_wins[i], 0, 0);
4366166124Srafan
4367262685Sdelphij	/* Attach a panel to each window */ 	/* Order is bottom up */
4368262685Sdelphij	my_panels[0] = new_panel(my_wins[0]); 	/* Push 0, order: stdscr-0 */
4369262685Sdelphij	my_panels[1] = new_panel(my_wins[1]); 	/* Push 1, order: stdscr-0-1 */
4370262685Sdelphij	my_panels[2] = new_panel(my_wins[2]); 	/* Push 2, order: stdscr-0-1-2 */
4371166124Srafan
4372262685Sdelphij	/* Update the stacking order. 2nd panel will be on top */
4373262685Sdelphij	update_panels();
4374166124Srafan
4375262685Sdelphij	/* Show it on the screen */
4376262685Sdelphij	doupdate();
4377262685Sdelphij	
4378262685Sdelphij	getch();
4379262685Sdelphij	endwin();
4380166124Srafan}
4381262685Sdelphij</SPAN
4382262685Sdelphij></PRE
4383262685Sdelphij></DIV
4384262685Sdelphij><P
4385262685Sdelphij>As you can see, above program follows a simple flow as explained. The windows
4386262685Sdelphijare created with newwin() and then they are attached to panels with new_panel().
4387262685SdelphijAs we attach one panel after another, the stack of panels gets updated. To put
4388262685Sdelphijthem on screen update_panels() and doupdate() are called.</P
4389262685Sdelphij></DIV
4390262685Sdelphij><DIV
4391262685SdelphijCLASS="SECT2"
4392262685Sdelphij><HR><H3
4393262685SdelphijCLASS="SECT2"
4394262685Sdelphij><A
4395262685SdelphijNAME="PANELBROWSING"
4396262685Sdelphij>16.3. Panel Window Browsing</A
4397262685Sdelphij></H3
4398262685Sdelphij><P
4399262685Sdelphij>A slightly complicated example is given below. This program creates 3
4400262685Sdelphijwindows which can be cycled through using tab. Have a look at the code.</P
4401262685Sdelphij><DIV
4402262685SdelphijCLASS="EXAMPLE"
4403262685Sdelphij><A
4404262685SdelphijNAME="PPABR"
4405262685Sdelphij></A
4406262685Sdelphij><P
4407262685Sdelphij><B
4408262685Sdelphij>Example 15.  Panel Window Browsing Example </B
4409262685Sdelphij></P
4410262685Sdelphij><PRE
4411262685SdelphijCLASS="PROGRAMLISTING"
4412262685Sdelphij><SPAN
4413262685SdelphijCLASS="INLINEMEDIAOBJECT"
4414262685Sdelphij>#include &#60;panel.h&#62;
4415166124Srafan
4416166124Srafan#define NLINES 10
4417166124Srafan#define NCOLS 40
4418166124Srafan
4419166124Srafanvoid init_wins(WINDOW **wins, int n);
4420166124Srafanvoid win_show(WINDOW *win, char *label, int label_color);
4421166124Srafanvoid print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color);
4422166124Srafan
4423166124Srafanint main()
4424262685Sdelphij{	WINDOW *my_wins[3];
4425262685Sdelphij	PANEL  *my_panels[3];
4426262685Sdelphij	PANEL  *top;
4427262685Sdelphij	int ch;
4428166124Srafan
4429262685Sdelphij	/* Initialize curses */
4430262685Sdelphij	initscr();
4431262685Sdelphij	start_color();
4432262685Sdelphij	cbreak();
4433262685Sdelphij	noecho();
4434262685Sdelphij	keypad(stdscr, TRUE);
4435166124Srafan
4436262685Sdelphij	/* Initialize all the colors */
4437262685Sdelphij	init_pair(1, COLOR_RED, COLOR_BLACK);
4438262685Sdelphij	init_pair(2, COLOR_GREEN, COLOR_BLACK);
4439262685Sdelphij	init_pair(3, COLOR_BLUE, COLOR_BLACK);
4440262685Sdelphij	init_pair(4, COLOR_CYAN, COLOR_BLACK);
4441166124Srafan
4442262685Sdelphij	init_wins(my_wins, 3);
4443262685Sdelphij	
4444262685Sdelphij	/* Attach a panel to each window */ 	/* Order is bottom up */
4445262685Sdelphij	my_panels[0] = new_panel(my_wins[0]); 	/* Push 0, order: stdscr-0 */
4446262685Sdelphij	my_panels[1] = new_panel(my_wins[1]); 	/* Push 1, order: stdscr-0-1 */
4447262685Sdelphij	my_panels[2] = new_panel(my_wins[2]); 	/* Push 2, order: stdscr-0-1-2 */
4448166124Srafan
4449262685Sdelphij	/* Set up the user pointers to the next panel */
4450262685Sdelphij	set_panel_userptr(my_panels[0], my_panels[1]);
4451262685Sdelphij	set_panel_userptr(my_panels[1], my_panels[2]);
4452262685Sdelphij	set_panel_userptr(my_panels[2], my_panels[0]);
4453166124Srafan
4454262685Sdelphij	/* Update the stacking order. 2nd panel will be on top */
4455262685Sdelphij	update_panels();
4456166124Srafan
4457262685Sdelphij	/* Show it on the screen */
4458262685Sdelphij	attron(COLOR_PAIR(4));
4459262685Sdelphij	mvprintw(LINES - 2, 0, "Use tab to browse through the windows (F1 to Exit)");
4460262685Sdelphij	attroff(COLOR_PAIR(4));
4461262685Sdelphij	doupdate();
4462166124Srafan
4463262685Sdelphij	top = my_panels[2];
4464262685Sdelphij	while((ch = getch()) != KEY_F(1))
4465262685Sdelphij	{	switch(ch)
4466262685Sdelphij		{	case 9:
4467262685Sdelphij				top = (PANEL *)panel_userptr(top);
4468262685Sdelphij				top_panel(top);
4469262685Sdelphij				break;
4470262685Sdelphij		}
4471262685Sdelphij		update_panels();
4472262685Sdelphij		doupdate();
4473262685Sdelphij	}
4474262685Sdelphij	endwin();
4475262685Sdelphij	return 0;
4476166124Srafan}
4477166124Srafan
4478166124Srafan/* Put all the windows */
4479166124Srafanvoid init_wins(WINDOW **wins, int n)
4480262685Sdelphij{	int x, y, i;
4481262685Sdelphij	char label[80];
4482166124Srafan
4483262685Sdelphij	y = 2;
4484262685Sdelphij	x = 10;
4485262685Sdelphij	for(i = 0; i &#60; n; ++i)
4486262685Sdelphij	{	wins[i] = newwin(NLINES, NCOLS, y, x);
4487262685Sdelphij		sprintf(label, "Window Number %d", i + 1);
4488262685Sdelphij		win_show(wins[i], label, i + 1);
4489262685Sdelphij		y += 3;
4490262685Sdelphij		x += 7;
4491262685Sdelphij	}
4492166124Srafan}
4493166124Srafan
4494166124Srafan/* Show the window with a border and a label */
4495166124Srafanvoid win_show(WINDOW *win, char *label, int label_color)
4496262685Sdelphij{	int startx, starty, height, width;
4497166124Srafan
4498262685Sdelphij	getbegyx(win, starty, startx);
4499262685Sdelphij	getmaxyx(win, height, width);
4500166124Srafan
4501262685Sdelphij	box(win, 0, 0);
4502262685Sdelphij	mvwaddch(win, 2, 0, ACS_LTEE); 
4503262685Sdelphij	mvwhline(win, 2, 1, ACS_HLINE, width - 2); 
4504262685Sdelphij	mvwaddch(win, 2, width - 1, ACS_RTEE); 
4505262685Sdelphij	
4506262685Sdelphij	print_in_middle(win, 1, 0, width, label, COLOR_PAIR(label_color));
4507166124Srafan}
4508166124Srafan
4509166124Srafanvoid print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color)
4510262685Sdelphij{	int length, x, y;
4511262685Sdelphij	float temp;
4512166124Srafan
4513262685Sdelphij	if(win == NULL)
4514262685Sdelphij		win = stdscr;
4515262685Sdelphij	getyx(win, y, x);
4516262685Sdelphij	if(startx != 0)
4517262685Sdelphij		x = startx;
4518262685Sdelphij	if(starty != 0)
4519262685Sdelphij		y = starty;
4520262685Sdelphij	if(width == 0)
4521262685Sdelphij		width = 80;
4522166124Srafan
4523262685Sdelphij	length = strlen(string);
4524262685Sdelphij	temp = (width - length)/ 2;
4525262685Sdelphij	x = startx + (int)temp;
4526262685Sdelphij	wattron(win, color);
4527262685Sdelphij	mvwprintw(win, y, x, "%s", string);
4528262685Sdelphij	wattroff(win, color);
4529262685Sdelphij	refresh();
4530262685Sdelphij}</SPAN
4531262685Sdelphij></PRE
4532262685Sdelphij></DIV
4533262685Sdelphij></DIV
4534262685Sdelphij><DIV
4535262685SdelphijCLASS="SECT2"
4536262685Sdelphij><HR><H3
4537262685SdelphijCLASS="SECT2"
4538262685Sdelphij><A
4539262685SdelphijNAME="USERPTRUSING"
4540262685Sdelphij>16.4. Using User Pointers</A
4541262685Sdelphij></H3
4542262685Sdelphij><P
4543262685Sdelphij>In the above example I used user pointers to find out the next window in the
4544262685Sdelphijcycle.  We can attach custom information to the panel by specifying a user
4545262685Sdelphijpointer, which can point to any information you want to store. In this case I
4546262685Sdelphijstored the pointer to the next panel in the cycle. User pointer for a panel can
4547262685Sdelphijbe set with the function <TT
4548262685SdelphijCLASS="LITERAL"
4549262685Sdelphij> set_panel_userptr()</TT
4550262685Sdelphij>.
4551262685SdelphijIt can be accessed using the function <TT
4552262685SdelphijCLASS="LITERAL"
4553262685Sdelphij>panel_userptr()</TT
4554262685Sdelphij> which will return the user pointer for the panel given as
4555262685Sdelphijargument. After finding the next panel in the cycle It's brought to the top by
4556262685Sdelphijthe function top_panel().  This function brings the panel given as argument to
4557262685Sdelphijthe top of the panel stack.  </P
4558262685Sdelphij></DIV
4559262685Sdelphij><DIV
4560262685SdelphijCLASS="SECT2"
4561262685Sdelphij><HR><H3
4562262685SdelphijCLASS="SECT2"
4563262685Sdelphij><A
4564262685SdelphijNAME="PANELMOVERESIZE"
4565262685Sdelphij>16.5. Moving and Resizing Panels</A
4566262685Sdelphij></H3
4567262685Sdelphij><P
4568262685Sdelphij>The function <TT
4569262685SdelphijCLASS="LITERAL"
4570262685Sdelphij>move_panel()</TT
4571262685Sdelphij> can be used to move a
4572262685Sdelphijpanel to the desired location. It does not change the position of the panel in
4573262685Sdelphijthe stack. Make sure that you use move_panel() instead mvwin() on the window
4574262685Sdelphijassociated with the panel.</P
4575262685Sdelphij><P
4576262685Sdelphij>Resizing a panel is slightly complex.  There is no straight forward function
4577262685Sdelphijjust to resize the window associated with a panel. A solution to resize a panel
4578262685Sdelphijis to create a new window with the desired sizes, change the window associated
4579262685Sdelphijwith the panel using replace_panel(). Don't forget to delete the old window. The
4580262685Sdelphijwindow associated with a panel can be found by using the function
4581262685Sdelphijpanel_window().</P
4582262685Sdelphij><P
4583262685Sdelphij>The following program shows these concepts, in supposedly simple program. You
4584262685Sdelphijcan cycle through the window with &lt;TAB&gt; as usual. To resize or move the
4585262685Sdelphijactive panel press 'r' for resize 'm' for moving. Then use arrow keys to resize
4586262685Sdelphijor move it to the desired way and press enter to end your resizing or moving.
4587262685SdelphijThis example makes use of user data to get the required data to do the
4588262685Sdelphijoperations. </P
4589262685Sdelphij><DIV
4590262685SdelphijCLASS="EXAMPLE"
4591262685Sdelphij><A
4592262685SdelphijNAME="PPARE"
4593262685Sdelphij></A
4594262685Sdelphij><P
4595262685Sdelphij><B
4596262685Sdelphij>Example 16.  Panel Moving and Resizing example </B
4597262685Sdelphij></P
4598262685Sdelphij><PRE
4599262685SdelphijCLASS="PROGRAMLISTING"
4600262685Sdelphij><SPAN
4601262685SdelphijCLASS="INLINEMEDIAOBJECT"
4602262685Sdelphij>#include &#60;panel.h&#62;
4603166124Srafan
4604166124Srafantypedef struct _PANEL_DATA {
4605262685Sdelphij	int x, y, w, h;
4606262685Sdelphij	char label[80]; 
4607262685Sdelphij	int label_color;
4608262685Sdelphij	PANEL *next;
4609166124Srafan}PANEL_DATA;
4610166124Srafan
4611166124Srafan#define NLINES 10
4612166124Srafan#define NCOLS 40
4613166124Srafan
4614166124Srafanvoid init_wins(WINDOW **wins, int n);
4615166124Srafanvoid win_show(WINDOW *win, char *label, int label_color);
4616166124Srafanvoid print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color);
4617166124Srafanvoid set_user_ptrs(PANEL **panels, int n);
4618166124Srafan
4619166124Srafanint main()
4620262685Sdelphij{	WINDOW *my_wins[3];
4621262685Sdelphij	PANEL  *my_panels[3];
4622262685Sdelphij	PANEL_DATA  *top;
4623262685Sdelphij	PANEL *stack_top;
4624262685Sdelphij	WINDOW *temp_win, *old_win;
4625262685Sdelphij	int ch;
4626262685Sdelphij	int newx, newy, neww, newh;
4627262685Sdelphij	int size = FALSE, move = FALSE;
4628166124Srafan
4629262685Sdelphij	/* Initialize curses */
4630262685Sdelphij	initscr();
4631262685Sdelphij	start_color();
4632262685Sdelphij	cbreak();
4633262685Sdelphij	noecho();
4634262685Sdelphij	keypad(stdscr, TRUE);
4635166124Srafan
4636262685Sdelphij	/* Initialize all the colors */
4637262685Sdelphij	init_pair(1, COLOR_RED, COLOR_BLACK);
4638262685Sdelphij	init_pair(2, COLOR_GREEN, COLOR_BLACK);
4639262685Sdelphij	init_pair(3, COLOR_BLUE, COLOR_BLACK);
4640262685Sdelphij	init_pair(4, COLOR_CYAN, COLOR_BLACK);
4641166124Srafan
4642262685Sdelphij	init_wins(my_wins, 3);
4643262685Sdelphij	
4644262685Sdelphij	/* Attach a panel to each window */ 	/* Order is bottom up */
4645262685Sdelphij	my_panels[0] = new_panel(my_wins[0]); 	/* Push 0, order: stdscr-0 */
4646262685Sdelphij	my_panels[1] = new_panel(my_wins[1]); 	/* Push 1, order: stdscr-0-1 */
4647262685Sdelphij	my_panels[2] = new_panel(my_wins[2]); 	/* Push 2, order: stdscr-0-1-2 */
4648166124Srafan
4649262685Sdelphij	set_user_ptrs(my_panels, 3);
4650262685Sdelphij	/* Update the stacking order. 2nd panel will be on top */
4651262685Sdelphij	update_panels();
4652166124Srafan
4653262685Sdelphij	/* Show it on the screen */
4654262685Sdelphij	attron(COLOR_PAIR(4));
4655262685Sdelphij	mvprintw(LINES - 3, 0, "Use 'm' for moving, 'r' for resizing");
4656262685Sdelphij	mvprintw(LINES - 2, 0, "Use tab to browse through the windows (F1 to Exit)");
4657262685Sdelphij	attroff(COLOR_PAIR(4));
4658262685Sdelphij	doupdate();
4659166124Srafan
4660262685Sdelphij	stack_top = my_panels[2];
4661262685Sdelphij	top = (PANEL_DATA *)panel_userptr(stack_top);
4662262685Sdelphij	newx = top-&#62;x;
4663262685Sdelphij	newy = top-&#62;y;
4664262685Sdelphij	neww = top-&#62;w;
4665262685Sdelphij	newh = top-&#62;h;
4666262685Sdelphij	while((ch = getch()) != KEY_F(1))
4667262685Sdelphij	{	switch(ch)
4668262685Sdelphij		{	case 9:		/* Tab */
4669262685Sdelphij				top = (PANEL_DATA *)panel_userptr(stack_top);
4670262685Sdelphij				top_panel(top-&#62;next);
4671262685Sdelphij				stack_top = top-&#62;next;
4672262685Sdelphij				top = (PANEL_DATA *)panel_userptr(stack_top);
4673262685Sdelphij				newx = top-&#62;x;
4674262685Sdelphij				newy = top-&#62;y;
4675262685Sdelphij				neww = top-&#62;w;
4676262685Sdelphij				newh = top-&#62;h;
4677262685Sdelphij				break;
4678262685Sdelphij			case 'r':	/* Re-Size*/
4679262685Sdelphij				size = TRUE;
4680262685Sdelphij				attron(COLOR_PAIR(4));
4681262685Sdelphij				mvprintw(LINES - 4, 0, "Entered Resizing :Use Arrow Keys to resize and press &#60;ENTER&#62; to end resizing");
4682262685Sdelphij				refresh();
4683262685Sdelphij				attroff(COLOR_PAIR(4));
4684262685Sdelphij				break;
4685262685Sdelphij			case 'm':	/* Move */
4686262685Sdelphij				attron(COLOR_PAIR(4));
4687262685Sdelphij				mvprintw(LINES - 4, 0, "Entered Moving: Use Arrow Keys to Move and press &#60;ENTER&#62; to end moving");
4688262685Sdelphij				refresh();
4689262685Sdelphij				attroff(COLOR_PAIR(4));
4690262685Sdelphij				move = TRUE;
4691262685Sdelphij				break;
4692262685Sdelphij			case KEY_LEFT:
4693262685Sdelphij				if(size == TRUE)
4694262685Sdelphij				{	--newx;
4695262685Sdelphij					++neww;
4696262685Sdelphij				}
4697262685Sdelphij				if(move == TRUE)
4698262685Sdelphij					--newx;
4699262685Sdelphij				break;
4700262685Sdelphij			case KEY_RIGHT:
4701262685Sdelphij				if(size == TRUE)
4702262685Sdelphij				{	++newx;
4703262685Sdelphij					--neww;
4704262685Sdelphij				}
4705262685Sdelphij				if(move == TRUE)
4706262685Sdelphij					++newx;
4707262685Sdelphij				break;
4708262685Sdelphij			case KEY_UP:
4709262685Sdelphij				if(size == TRUE)
4710262685Sdelphij				{	--newy;
4711262685Sdelphij					++newh;
4712262685Sdelphij				}
4713262685Sdelphij				if(move == TRUE)
4714262685Sdelphij					--newy;
4715262685Sdelphij				break;
4716262685Sdelphij			case KEY_DOWN:
4717262685Sdelphij				if(size == TRUE)
4718262685Sdelphij				{	++newy;
4719262685Sdelphij					--newh;
4720262685Sdelphij				}
4721262685Sdelphij				if(move == TRUE)
4722262685Sdelphij					++newy;
4723262685Sdelphij				break;
4724262685Sdelphij			case 10:	/* Enter */
4725262685Sdelphij				move(LINES - 4, 0);
4726262685Sdelphij				clrtoeol();
4727262685Sdelphij				refresh();
4728262685Sdelphij				if(size == TRUE)
4729262685Sdelphij				{	old_win = panel_window(stack_top);
4730262685Sdelphij					temp_win = newwin(newh, neww, newy, newx);
4731262685Sdelphij					replace_panel(stack_top, temp_win);
4732262685Sdelphij					win_show(temp_win, top-&#62;label, top-&#62;label_color); 
4733262685Sdelphij					delwin(old_win);
4734262685Sdelphij					size = FALSE;
4735262685Sdelphij				}
4736262685Sdelphij				if(move == TRUE)
4737262685Sdelphij				{	move_panel(stack_top, newy, newx);
4738262685Sdelphij					move = FALSE;
4739262685Sdelphij				}
4740262685Sdelphij				break;
4741262685Sdelphij			
4742262685Sdelphij		}
4743262685Sdelphij		attron(COLOR_PAIR(4));
4744262685Sdelphij		mvprintw(LINES - 3, 0, "Use 'm' for moving, 'r' for resizing");
4745262685Sdelphij	    	mvprintw(LINES - 2, 0, "Use tab to browse through the windows (F1 to Exit)");
4746262685Sdelphij	    	attroff(COLOR_PAIR(4));
4747262685Sdelphij	        refresh();	
4748262685Sdelphij		update_panels();
4749262685Sdelphij		doupdate();
4750262685Sdelphij	}
4751262685Sdelphij	endwin();
4752262685Sdelphij	return 0;
4753166124Srafan}
4754166124Srafan
4755166124Srafan/* Put all the windows */
4756166124Srafanvoid init_wins(WINDOW **wins, int n)
4757262685Sdelphij{	int x, y, i;
4758262685Sdelphij	char label[80];
4759166124Srafan
4760262685Sdelphij	y = 2;
4761262685Sdelphij	x = 10;
4762262685Sdelphij	for(i = 0; i &#60; n; ++i)
4763262685Sdelphij	{	wins[i] = newwin(NLINES, NCOLS, y, x);
4764262685Sdelphij		sprintf(label, "Window Number %d", i + 1);
4765262685Sdelphij		win_show(wins[i], label, i + 1);
4766262685Sdelphij		y += 3;
4767262685Sdelphij		x += 7;
4768262685Sdelphij	}
4769166124Srafan}
4770166124Srafan
4771166124Srafan/* Set the PANEL_DATA structures for individual panels */
4772166124Srafanvoid set_user_ptrs(PANEL **panels, int n)
4773262685Sdelphij{	PANEL_DATA *ptrs;
4774262685Sdelphij	WINDOW *win;
4775262685Sdelphij	int x, y, w, h, i;
4776262685Sdelphij	char temp[80];
4777262685Sdelphij	
4778262685Sdelphij	ptrs = (PANEL_DATA *)calloc(n, sizeof(PANEL_DATA));
4779166124Srafan
4780262685Sdelphij	for(i = 0;i &#60; n; ++i)
4781262685Sdelphij	{	win = panel_window(panels[i]);
4782262685Sdelphij		getbegyx(win, y, x);
4783262685Sdelphij		getmaxyx(win, h, w);
4784262685Sdelphij		ptrs[i].x = x;
4785262685Sdelphij		ptrs[i].y = y;
4786262685Sdelphij		ptrs[i].w = w;
4787262685Sdelphij		ptrs[i].h = h;
4788262685Sdelphij		sprintf(temp, "Window Number %d", i + 1);
4789262685Sdelphij		strcpy(ptrs[i].label, temp);
4790262685Sdelphij		ptrs[i].label_color = i + 1;
4791262685Sdelphij		if(i + 1 == n)
4792262685Sdelphij			ptrs[i].next = panels[0];
4793262685Sdelphij		else
4794262685Sdelphij			ptrs[i].next = panels[i + 1];
4795262685Sdelphij		set_panel_userptr(panels[i], &#38;ptrs[i]);
4796262685Sdelphij	}
4797166124Srafan}
4798166124Srafan
4799166124Srafan/* Show the window with a border and a label */
4800166124Srafanvoid win_show(WINDOW *win, char *label, int label_color)
4801262685Sdelphij{	int startx, starty, height, width;
4802166124Srafan
4803262685Sdelphij	getbegyx(win, starty, startx);
4804262685Sdelphij	getmaxyx(win, height, width);
4805166124Srafan
4806262685Sdelphij	box(win, 0, 0);
4807262685Sdelphij	mvwaddch(win, 2, 0, ACS_LTEE); 
4808262685Sdelphij	mvwhline(win, 2, 1, ACS_HLINE, width - 2); 
4809262685Sdelphij	mvwaddch(win, 2, width - 1, ACS_RTEE); 
4810262685Sdelphij	
4811262685Sdelphij	print_in_middle(win, 1, 0, width, label, COLOR_PAIR(label_color));
4812166124Srafan}
4813166124Srafan
4814166124Srafanvoid print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color)
4815262685Sdelphij{	int length, x, y;
4816262685Sdelphij	float temp;
4817166124Srafan
4818262685Sdelphij	if(win == NULL)
4819262685Sdelphij		win = stdscr;
4820262685Sdelphij	getyx(win, y, x);
4821262685Sdelphij	if(startx != 0)
4822262685Sdelphij		x = startx;
4823262685Sdelphij	if(starty != 0)
4824262685Sdelphij		y = starty;
4825262685Sdelphij	if(width == 0)
4826262685Sdelphij		width = 80;
4827166124Srafan
4828262685Sdelphij	length = strlen(string);
4829262685Sdelphij	temp = (width - length)/ 2;
4830262685Sdelphij	x = startx + (int)temp;
4831262685Sdelphij	wattron(win, color);
4832262685Sdelphij	mvwprintw(win, y, x, "%s", string);
4833262685Sdelphij	wattroff(win, color);
4834262685Sdelphij	refresh();
4835262685Sdelphij}</SPAN
4836262685Sdelphij></PRE
4837262685Sdelphij></DIV
4838262685Sdelphij><P
4839262685Sdelphij>Concentrate on the main while loop. Once it finds out the type of key pressed,
4840262685Sdelphijit takes appropriate action. If 'r' is pressed resizing mode is started. After
4841262685Sdelphijthis the new sizes are updated as the user presses the arrow keys. When the user
4842262685Sdelphijpresses &lt;ENTER&gt; present selection ends and panel is resized by using the
4843262685Sdelphijconcept explained.  While in resizing mode the program doesn't show how the
4844262685Sdelphijwindow is getting resized.  It's left as an exercise to the reader to print a
4845262685Sdelphijdotted border while it gets resized to a new position. </P
4846262685Sdelphij><P
4847262685Sdelphij>When the user presses 'm' the move mode starts. This is a bit simpler than
4848262685Sdelphijresizing.  As the arrow keys are pressed the new position is updated and
4849262685Sdelphijpressing of &lt;ENTER&gt; causes the panel to be moved by calling the function
4850262685Sdelphijmove_panel().</P
4851262685Sdelphij><P
4852262685Sdelphij>In this program the user data which is represented as PANEL_DATA, plays very
4853262685Sdelphijimportant role in finding the associated information with a panel. As written in
4854262685Sdelphijthe comments, the PANEL_DATA stores the panel sizes, label, label color and a
4855262685Sdelphijpointer to the next panel in the cycle.</P
4856262685Sdelphij></DIV
4857262685Sdelphij><DIV
4858262685SdelphijCLASS="SECT2"
4859262685Sdelphij><HR><H3
4860262685SdelphijCLASS="SECT2"
4861262685Sdelphij><A
4862262685SdelphijNAME="PANELSHOWHIDE"
4863262685Sdelphij>16.6. Hiding and Showing Panels</A
4864262685Sdelphij></H3
4865262685Sdelphij><P
4866262685Sdelphij>A Panel can be hidden by using the function hide_panel(). This function merely
4867262685Sdelphijremoves it form the stack of panels, thus hiding it on the screen once you do
4868262685Sdelphijupdate_panels() and doupdate(). It doesn't destroy the PANEL structure
4869262685Sdelphijassociated with the hidden panel.  It can be shown again by using the
4870262685Sdelphijshow_panel() function.</P
4871262685Sdelphij><P
4872262685Sdelphij>The following program shows the hiding of panels. Press 'a' or 'b' or 'c' to
4873262685Sdelphijshow or hide first, second and third windows respectively. It uses a user data
4874262685Sdelphijwith a small variable hide, which keeps track of whether the window is hidden or
4875262685Sdelphijnot. For some reason the function
4876262685Sdelphij<TT
4877262685SdelphijCLASS="LITERAL"
4878262685Sdelphij>panel_hidden()</TT
4879262685Sdelphij> which tells whether a panel is
4880262685Sdelphijhidden or not is not working.  A bug report was also presented by Michael Andres
4881262685Sdelphij<A
4882262685SdelphijHREF="http://www.geocrawler.com/archives/3/344/1999/9/0/2643549/"
4883262685SdelphijTARGET="_top"
4884262685Sdelphij> here</A
4885262685Sdelphij></P
4886262685Sdelphij><DIV
4887262685SdelphijCLASS="EXAMPLE"
4888262685Sdelphij><A
4889262685SdelphijNAME="PPAHI"
4890262685Sdelphij></A
4891262685Sdelphij><P
4892262685Sdelphij><B
4893262685Sdelphij>Example 17.  Panel Hiding and Showing example </B
4894262685Sdelphij></P
4895262685Sdelphij><PRE
4896262685SdelphijCLASS="PROGRAMLISTING"
4897262685Sdelphij><SPAN
4898262685SdelphijCLASS="INLINEMEDIAOBJECT"
4899262685Sdelphij>#include &#60;panel.h&#62;
4900166124Srafan
4901166124Srafantypedef struct _PANEL_DATA {
4902262685Sdelphij	int hide;	/* TRUE if panel is hidden */
4903166124Srafan}PANEL_DATA;
4904166124Srafan
4905166124Srafan#define NLINES 10
4906166124Srafan#define NCOLS 40
4907166124Srafan
4908166124Srafanvoid init_wins(WINDOW **wins, int n);
4909166124Srafanvoid win_show(WINDOW *win, char *label, int label_color);
4910166124Srafanvoid print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color);
4911166124Srafan
4912166124Srafanint main()
4913262685Sdelphij{	WINDOW *my_wins[3];
4914262685Sdelphij	PANEL  *my_panels[3];
4915262685Sdelphij	PANEL_DATA panel_datas[3];
4916262685Sdelphij	PANEL_DATA *temp;
4917262685Sdelphij	int ch;
4918166124Srafan
4919262685Sdelphij	/* Initialize curses */
4920262685Sdelphij	initscr();
4921262685Sdelphij	start_color();
4922262685Sdelphij	cbreak();
4923262685Sdelphij	noecho();
4924262685Sdelphij	keypad(stdscr, TRUE);
4925166124Srafan
4926262685Sdelphij	/* Initialize all the colors */
4927262685Sdelphij	init_pair(1, COLOR_RED, COLOR_BLACK);
4928262685Sdelphij	init_pair(2, COLOR_GREEN, COLOR_BLACK);
4929262685Sdelphij	init_pair(3, COLOR_BLUE, COLOR_BLACK);
4930262685Sdelphij	init_pair(4, COLOR_CYAN, COLOR_BLACK);
4931166124Srafan
4932262685Sdelphij	init_wins(my_wins, 3);
4933262685Sdelphij	
4934262685Sdelphij	/* Attach a panel to each window */ 	/* Order is bottom up */
4935262685Sdelphij	my_panels[0] = new_panel(my_wins[0]); 	/* Push 0, order: stdscr-0 */
4936262685Sdelphij	my_panels[1] = new_panel(my_wins[1]); 	/* Push 1, order: stdscr-0-1 */
4937262685Sdelphij	my_panels[2] = new_panel(my_wins[2]); 	/* Push 2, order: stdscr-0-1-2 */
4938166124Srafan
4939262685Sdelphij	/* Initialize panel datas saying that nothing is hidden */
4940262685Sdelphij	panel_datas[0].hide = FALSE;
4941262685Sdelphij	panel_datas[1].hide = FALSE;
4942262685Sdelphij	panel_datas[2].hide = FALSE;
4943166124Srafan
4944262685Sdelphij	set_panel_userptr(my_panels[0], &#38;panel_datas[0]);
4945262685Sdelphij	set_panel_userptr(my_panels[1], &#38;panel_datas[1]);
4946262685Sdelphij	set_panel_userptr(my_panels[2], &#38;panel_datas[2]);
4947166124Srafan
4948262685Sdelphij	/* Update the stacking order. 2nd panel will be on top */
4949262685Sdelphij	update_panels();
4950166124Srafan
4951262685Sdelphij	/* Show it on the screen */
4952262685Sdelphij	attron(COLOR_PAIR(4));
4953262685Sdelphij	mvprintw(LINES - 3, 0, "Show or Hide a window with 'a'(first window)  'b'(Second Window)  'c'(Third Window)");
4954262685Sdelphij	mvprintw(LINES - 2, 0, "F1 to Exit");
4955166124Srafan
4956262685Sdelphij	attroff(COLOR_PAIR(4));
4957262685Sdelphij	doupdate();
4958262685Sdelphij	
4959262685Sdelphij	while((ch = getch()) != KEY_F(1))
4960262685Sdelphij	{	switch(ch)
4961262685Sdelphij		{	case 'a':			
4962262685Sdelphij				temp = (PANEL_DATA *)panel_userptr(my_panels[0]);
4963262685Sdelphij				if(temp-&#62;hide == FALSE)
4964262685Sdelphij				{	hide_panel(my_panels[0]);
4965262685Sdelphij					temp-&#62;hide = TRUE;
4966262685Sdelphij				}
4967262685Sdelphij				else
4968262685Sdelphij				{	show_panel(my_panels[0]);
4969262685Sdelphij					temp-&#62;hide = FALSE;
4970262685Sdelphij				}
4971262685Sdelphij				break;
4972262685Sdelphij			case 'b':
4973262685Sdelphij				temp = (PANEL_DATA *)panel_userptr(my_panels[1]);
4974262685Sdelphij				if(temp-&#62;hide == FALSE)
4975262685Sdelphij				{	hide_panel(my_panels[1]);
4976262685Sdelphij					temp-&#62;hide = TRUE;
4977262685Sdelphij				}
4978262685Sdelphij				else
4979262685Sdelphij				{	show_panel(my_panels[1]);
4980262685Sdelphij					temp-&#62;hide = FALSE;
4981262685Sdelphij				}
4982262685Sdelphij				break;
4983262685Sdelphij			case 'c':
4984262685Sdelphij				temp = (PANEL_DATA *)panel_userptr(my_panels[2]);
4985262685Sdelphij				if(temp-&#62;hide == FALSE)
4986262685Sdelphij				{	hide_panel(my_panels[2]);
4987262685Sdelphij					temp-&#62;hide = TRUE;
4988262685Sdelphij				}
4989262685Sdelphij				else
4990262685Sdelphij				{	show_panel(my_panels[2]);
4991262685Sdelphij					temp-&#62;hide = FALSE;
4992262685Sdelphij				}
4993262685Sdelphij				break;
4994262685Sdelphij		}
4995262685Sdelphij		update_panels();
4996262685Sdelphij		doupdate();
4997262685Sdelphij	}
4998262685Sdelphij	endwin();
4999262685Sdelphij	return 0;
5000166124Srafan}
5001166124Srafan
5002166124Srafan/* Put all the windows */
5003166124Srafanvoid init_wins(WINDOW **wins, int n)
5004262685Sdelphij{	int x, y, i;
5005262685Sdelphij	char label[80];
5006166124Srafan
5007262685Sdelphij	y = 2;
5008262685Sdelphij	x = 10;
5009262685Sdelphij	for(i = 0; i &#60; n; ++i)
5010262685Sdelphij	{	wins[i] = newwin(NLINES, NCOLS, y, x);
5011262685Sdelphij		sprintf(label, "Window Number %d", i + 1);
5012262685Sdelphij		win_show(wins[i], label, i + 1);
5013262685Sdelphij		y += 3;
5014262685Sdelphij		x += 7;
5015262685Sdelphij	}
5016166124Srafan}
5017166124Srafan
5018166124Srafan/* Show the window with a border and a label */
5019166124Srafanvoid win_show(WINDOW *win, char *label, int label_color)
5020262685Sdelphij{	int startx, starty, height, width;
5021166124Srafan
5022262685Sdelphij	getbegyx(win, starty, startx);
5023262685Sdelphij	getmaxyx(win, height, width);
5024166124Srafan
5025262685Sdelphij	box(win, 0, 0);
5026262685Sdelphij	mvwaddch(win, 2, 0, ACS_LTEE); 
5027262685Sdelphij	mvwhline(win, 2, 1, ACS_HLINE, width - 2); 
5028262685Sdelphij	mvwaddch(win, 2, width - 1, ACS_RTEE); 
5029262685Sdelphij	
5030262685Sdelphij	print_in_middle(win, 1, 0, width, label, COLOR_PAIR(label_color));
5031166124Srafan}
5032166124Srafan
5033166124Srafanvoid print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color)
5034262685Sdelphij{	int length, x, y;
5035262685Sdelphij	float temp;
5036166124Srafan
5037262685Sdelphij	if(win == NULL)
5038262685Sdelphij		win = stdscr;
5039262685Sdelphij	getyx(win, y, x);
5040262685Sdelphij	if(startx != 0)
5041262685Sdelphij		x = startx;
5042262685Sdelphij	if(starty != 0)
5043262685Sdelphij		y = starty;
5044262685Sdelphij	if(width == 0)
5045262685Sdelphij		width = 80;
5046166124Srafan
5047262685Sdelphij	length = strlen(string);
5048262685Sdelphij	temp = (width - length)/ 2;
5049262685Sdelphij	x = startx + (int)temp;
5050262685Sdelphij	wattron(win, color);
5051262685Sdelphij	mvwprintw(win, y, x, "%s", string);
5052262685Sdelphij	wattroff(win, color);
5053262685Sdelphij	refresh();
5054262685Sdelphij}</SPAN
5055262685Sdelphij></PRE
5056262685Sdelphij></DIV
5057262685Sdelphij></DIV
5058262685Sdelphij><DIV
5059262685SdelphijCLASS="SECT2"
5060262685Sdelphij><HR><H3
5061262685SdelphijCLASS="SECT2"
5062262685Sdelphij><A
5063262685SdelphijNAME="PANELABOVE"
5064262685Sdelphij>16.7. panel_above() and panel_below() Functions</A
5065262685Sdelphij></H3
5066262685Sdelphij><P
5067262685Sdelphij>The functions <TT
5068262685SdelphijCLASS="LITERAL"
5069262685Sdelphij>panel_above()</TT
5070262685Sdelphij> and
5071262685Sdelphij<TT
5072262685SdelphijCLASS="LITERAL"
5073262685Sdelphij>panel_below()</TT
5074262685Sdelphij> can be used to find out the panel
5075262685Sdelphijabove and below a panel. If the argument to these functions is NULL, then they
5076262685Sdelphijreturn a pointer to bottom panel and top panel respectively.</P
5077262685Sdelphij></DIV
5078262685Sdelphij></DIV
5079262685Sdelphij><DIV
5080262685SdelphijCLASS="SECT1"
5081262685Sdelphij><HR><H2
5082262685SdelphijCLASS="SECT1"
5083262685Sdelphij><A
5084262685SdelphijNAME="MENUS"
5085262685Sdelphij>17. Menus Library</A
5086262685Sdelphij></H2
5087262685Sdelphij><P
5088262685Sdelphij>The menus library provides a nice extension to basic curses, through which you
5089262685Sdelphijcan create menus. It provides a set of functions to create menus. But they have
5090262685Sdelphijto be customized to give a nicer look, with colors etc. Let's get into the
5091262685Sdelphijdetails.</P
5092262685Sdelphij><P
5093262685Sdelphij>A menu is a screen display that assists the user to choose some subset of a
5094262685Sdelphijgiven set of items. To put it simple, a menu is a collection of items from which
5095262685Sdelphijone or more items can be chosen. Some readers might not be aware of multiple
5096262685Sdelphijitem selection capability.  Menu library provides functionality to write menus
5097262685Sdelphijfrom which the user can chose more than one item as the preferred choice. This
5098262685Sdelphijis dealt with in a later section. Now it is time for some rudiments.</P
5099262685Sdelphij><DIV
5100262685SdelphijCLASS="SECT2"
5101262685Sdelphij><HR><H3
5102262685SdelphijCLASS="SECT2"
5103262685Sdelphij><A
5104262685SdelphijNAME="MENUBASICS"
5105262685Sdelphij>17.1. The Basics</A
5106262685Sdelphij></H3
5107262685Sdelphij><P
5108262685Sdelphij>To create menus, you first create items, and then post the menu to the display.
5109262685SdelphijAfter that, all the processing of user responses is done in an elegant function
5110262685Sdelphijmenu_driver() which is the work horse of any menu program. </P
5111262685Sdelphij><P
5112262685Sdelphij>The general flow of control of a menu program looks like this.
5113262685Sdelphij<P
5114262685Sdelphij></P
5115262685Sdelphij><OL
5116262685SdelphijTYPE="1"
5117262685Sdelphij><LI
5118262685Sdelphij><P
5119262685Sdelphij>Initialize curses</P
5120262685Sdelphij></LI
5121262685Sdelphij><LI
5122262685Sdelphij><P
5123262685Sdelphij>Create items using new_item(). You can specify a name and description for the
5124262685Sdelphijitems.</P
5125262685Sdelphij></LI
5126262685Sdelphij><LI
5127262685Sdelphij><P
5128262685Sdelphij>Create the menu with new_menu() by specifying the items to be attached with.</P
5129262685Sdelphij></LI
5130262685Sdelphij><LI
5131262685Sdelphij><P
5132262685Sdelphij>Post the menu with menu_post() and refresh the screen.</P
5133262685Sdelphij></LI
5134262685Sdelphij><LI
5135262685Sdelphij><P
5136262685Sdelphij>Process the user requests with a loop and do necessary updates to menu with
5137262685Sdelphijmenu_driver.</P
5138262685Sdelphij></LI
5139262685Sdelphij><LI
5140262685Sdelphij><P
5141262685Sdelphij>Unpost the menu with menu_unpost()</P
5142262685Sdelphij></LI
5143262685Sdelphij><LI
5144262685Sdelphij><P
5145262685Sdelphij>Free the memory allocated to menu by free_menu()</P
5146262685Sdelphij></LI
5147262685Sdelphij><LI
5148262685Sdelphij><P
5149262685Sdelphij>Free the memory allocated to the items with free_item() </P
5150262685Sdelphij></LI
5151262685Sdelphij><LI
5152262685Sdelphij><P
5153262685Sdelphij>End curses </P
5154262685Sdelphij></LI
5155262685Sdelphij></OL
5156262685Sdelphij></P
5157262685Sdelphij><P
5158262685Sdelphij>Let's see a program which prints a simple menu and updates the current selection
5159262685Sdelphijwith up, down arrows. </P
5160262685Sdelphij></DIV
5161262685Sdelphij><DIV
5162262685SdelphijCLASS="SECT2"
5163262685Sdelphij><HR><H3
5164262685SdelphijCLASS="SECT2"
5165262685Sdelphij><A
5166262685SdelphijNAME="COMPILEMENUS"
5167262685Sdelphij>17.2. Compiling With the Menu Library</A
5168262685Sdelphij></H3
5169262685Sdelphij><P
5170262685Sdelphij>To use menu library functions, you have to include menu.h and to link the
5171262685Sdelphijprogram with menu library the flag -lmenu should be added along with -lncurses
5172262685Sdelphijin that order.</P
5173262685Sdelphij><PRE
5174262685SdelphijCLASS="PROGRAMLISTING"
5175262685Sdelphij>    #include &lt;menu.h&gt;
5176166124Srafan    .
5177166124Srafan    .
5178166124Srafan    .
5179166124Srafan
5180262685Sdelphij    compile and link: gcc &lt;program file&gt; -lmenu -lncurses</PRE
5181262685Sdelphij><DIV
5182262685SdelphijCLASS="EXAMPLE"
5183262685Sdelphij><A
5184262685SdelphijNAME="MMESI"
5185262685Sdelphij></A
5186262685Sdelphij><P
5187262685Sdelphij><B
5188262685Sdelphij>Example 18. Menu Basics </B
5189262685Sdelphij></P
5190262685Sdelphij><PRE
5191262685SdelphijCLASS="PROGRAMLISTING"
5192262685Sdelphij><SPAN
5193262685SdelphijCLASS="INLINEMEDIAOBJECT"
5194262685Sdelphij>#include &#60;curses.h&#62;
5195262685Sdelphij#include &#60;menu.h&#62;
5196166124Srafan
5197166124Srafan#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
5198262685Sdelphij#define CTRLD 	4
5199166124Srafan
5200166124Srafanchar *choices[] = {
5201166124Srafan                        "Choice 1",
5202166124Srafan                        "Choice 2",
5203166124Srafan                        "Choice 3",
5204166124Srafan                        "Choice 4",
5205166124Srafan                        "Exit",
5206166124Srafan                  };
5207166124Srafan
5208166124Srafanint main()
5209262685Sdelphij{	ITEM **my_items;
5210262685Sdelphij	int c;				
5211262685Sdelphij	MENU *my_menu;
5212262685Sdelphij	int n_choices, i;
5213262685Sdelphij	ITEM *cur_item;
5214262685Sdelphij	
5215262685Sdelphij	
5216262685Sdelphij	initscr();
5217262685Sdelphij	cbreak();
5218262685Sdelphij	noecho();
5219262685Sdelphij	keypad(stdscr, TRUE);
5220262685Sdelphij	
5221262685Sdelphij	n_choices = ARRAY_SIZE(choices);
5222262685Sdelphij	my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *));
5223166124Srafan
5224262685Sdelphij	for(i = 0; i &#60; n_choices; ++i)
5225262685Sdelphij	        my_items[i] = new_item(choices[i], choices[i]);
5226262685Sdelphij	my_items[n_choices] = (ITEM *)NULL;
5227166124Srafan
5228262685Sdelphij	my_menu = new_menu((ITEM **)my_items);
5229262685Sdelphij	mvprintw(LINES - 2, 0, "F1 to Exit");
5230262685Sdelphij	post_menu(my_menu);
5231262685Sdelphij	refresh();
5232166124Srafan
5233262685Sdelphij	while((c = getch()) != KEY_F(1))
5234262685Sdelphij	{   switch(c)
5235262685Sdelphij	    {	case KEY_DOWN:
5236262685Sdelphij		        menu_driver(my_menu, REQ_DOWN_ITEM);
5237262685Sdelphij				break;
5238262685Sdelphij			case KEY_UP:
5239262685Sdelphij				menu_driver(my_menu, REQ_UP_ITEM);
5240262685Sdelphij				break;
5241262685Sdelphij		}
5242262685Sdelphij	}	
5243166124Srafan
5244262685Sdelphij	free_item(my_items[0]);
5245262685Sdelphij	free_item(my_items[1]);
5246262685Sdelphij	free_menu(my_menu);
5247262685Sdelphij	endwin();
5248166124Srafan}
5249262685Sdelphij	</SPAN
5250262685Sdelphij></PRE
5251262685Sdelphij></DIV
5252262685Sdelphij><P
5253262685Sdelphij>This program demonstrates the basic concepts involved in creating a menu using
5254262685Sdelphijmenus library.  First we create the items using new_item() and then attach them
5255262685Sdelphijto the menu with new_menu() function. After posting the menu and refreshing the
5256262685Sdelphijscreen, the main processing loop starts. It reads user input and takes
5257262685Sdelphijcorresponding action. The function menu_driver() is the main work horse of the
5258262685Sdelphijmenu system. The second parameter to this function tells what's to be done with
5259262685Sdelphijthe menu. According to the parameter, menu_driver() does the corresponding task.
5260262685SdelphijThe value can be either a menu navigational request, an ascii character, or a
5261262685SdelphijKEY_MOUSE special key associated with a mouse event.</P
5262262685Sdelphij><P
5263262685Sdelphij>The menu_driver accepts following navigational requests. 
5264262685Sdelphij<PRE
5265262685SdelphijCLASS="PROGRAMLISTING"
5266262685Sdelphij>&#13;     REQ_LEFT_ITEM         Move left to an item.
5267166124Srafan     REQ_RIGHT_ITEM      Move right to an item.
5268166124Srafan     REQ_UP_ITEM         Move up to an item.
5269166124Srafan     REQ_DOWN_ITEM       Move down to an item.
5270166124Srafan     REQ_SCR_ULINE       Scroll up a line.
5271166124Srafan     REQ_SCR_DLINE          Scroll down a line.
5272166124Srafan     REQ_SCR_DPAGE          Scroll down a page.
5273166124Srafan     REQ_SCR_UPAGE         Scroll up a page.
5274166124Srafan     REQ_FIRST_ITEM     Move to the first item.
5275166124Srafan     REQ_LAST_ITEM         Move to the last item.
5276166124Srafan     REQ_NEXT_ITEM         Move to the next item.
5277166124Srafan     REQ_PREV_ITEM         Move to the previous item. 
5278166124Srafan     REQ_TOGGLE_ITEM     Select/deselect an item.
5279166124Srafan     REQ_CLEAR_PATTERN     Clear the menu pattern buffer.
5280166124Srafan     REQ_BACK_PATTERN      Delete the previous character from the pattern buffer.
5281166124Srafan     REQ_NEXT_MATCH     Move to the next item matching the pattern match.
5282262685Sdelphij     REQ_PREV_MATCH     Move to the previous item matching the pattern match.&#13;</PRE
5283262685Sdelphij></P
5284262685Sdelphij><P
5285262685Sdelphij>Don't get overwhelmed by the number of options. We will see them slowly one
5286262685Sdelphijafter another. The options of interest in this example are REQ_UP_ITEM and
5287262685SdelphijREQ_DOWN_ITEM.  These two options when passed to menu_driver, menu driver
5288262685Sdelphijupdates the current item to one item up or down respectively.</P
5289262685Sdelphij></DIV
5290262685Sdelphij><DIV
5291262685SdelphijCLASS="SECT2"
5292262685Sdelphij><HR><H3
5293262685SdelphijCLASS="SECT2"
5294262685Sdelphij><A
5295262685SdelphijNAME="MENUDRIVER"
5296262685Sdelphij>17.3. Menu Driver: The work horse of the menu system</A
5297262685Sdelphij></H3
5298262685Sdelphij><P
5299262685Sdelphij>As you have seen in the above example, menu_driver plays an important role in
5300262685Sdelphijupdating the menu. It is very important to understand various options it takes
5301262685Sdelphijand what they do.  As explained above, the second parameter to menu_driver() can
5302262685Sdelphijbe either a navigational request, a printable character or a KEY_MOUSE key.
5303262685SdelphijLet's dissect the different navigational requests.</P
5304262685Sdelphij><P
5305262685Sdelphij></P
5306262685Sdelphij><UL
5307262685Sdelphij><LI
5308262685Sdelphij><P
5309262685Sdelphij><SPAN
5310262685SdelphijCLASS="emphasis"
5311262685Sdelphij><I
5312262685SdelphijCLASS="EMPHASIS"
5313262685Sdelphij>REQ_LEFT_ITEM and REQ_RIGHT_ITEM</I
5314262685Sdelphij></SPAN
5315262685Sdelphij></P
5316262685Sdelphij><P
5317262685Sdelphij>A Menu can be displayed with multiple columns for more than one item. This can
5318262685Sdelphijbe done by using the <TT
5319262685SdelphijCLASS="LITERAL"
5320262685Sdelphij>menu_format()</TT
5321262685Sdelphij>function.
5322262685SdelphijWhen a multi columnar menu is displayed these requests cause the menu driver to
5323262685Sdelphijmove the current selection to left or right.</P
5324262685Sdelphij></LI
5325262685Sdelphij><LI
5326262685Sdelphij><P
5327262685Sdelphij><SPAN
5328262685SdelphijCLASS="emphasis"
5329262685Sdelphij><I
5330262685SdelphijCLASS="EMPHASIS"
5331262685Sdelphij>REQ_UP_ITEM and REQ_DOWN_ITEM </I
5332262685Sdelphij></SPAN
5333262685Sdelphij> </P
5334262685Sdelphij><P
5335262685Sdelphij>These two options you have seen in the above example. These options when given,
5336262685Sdelphijmakes the menu_driver to move the current selection to an item up or down.</P
5337262685Sdelphij></LI
5338262685Sdelphij><LI
5339262685Sdelphij><P
5340262685Sdelphij> <SPAN
5341262685SdelphijCLASS="emphasis"
5342262685Sdelphij><I
5343262685SdelphijCLASS="EMPHASIS"
5344262685Sdelphij>REQ_SCR_* options</I
5345262685Sdelphij></SPAN
5346262685Sdelphij> </P
5347262685Sdelphij><P
5348262685Sdelphij>The four options REQ_SCR_ULINE, REQ_SCR_DLINE, REQ_SCR_DPAGE, REQ_SCR_UPAGE are
5349262685Sdelphijrelated to scrolling. If all the items in the menu cannot be displayed in the
5350262685Sdelphijmenu sub window, then the menu is scrollable. These requests can be given to the
5351262685Sdelphijmenu_driver to do the scrolling either one line up, down or one page down or up
5352262685Sdelphijrespectively. </P
5353262685Sdelphij></LI
5354262685Sdelphij><LI
5355262685Sdelphij><P
5356262685Sdelphij><SPAN
5357262685SdelphijCLASS="emphasis"
5358262685Sdelphij><I
5359262685SdelphijCLASS="EMPHASIS"
5360262685Sdelphij>REQ_FIRST_ITEM, REQ_LAST_ITEM, REQ_NEXT_ITEM and
5361262685SdelphijREQ_PREV_ITEM </I
5362262685Sdelphij></SPAN
5363262685Sdelphij> </P
5364262685Sdelphij><P
5365262685Sdelphij>These requests are self explanatory.</P
5366262685Sdelphij></LI
5367262685Sdelphij><LI
5368262685Sdelphij><P
5369262685Sdelphij> <SPAN
5370262685SdelphijCLASS="emphasis"
5371262685Sdelphij><I
5372262685SdelphijCLASS="EMPHASIS"
5373262685Sdelphij>REQ_TOGGLE_ITEM</I
5374262685Sdelphij></SPAN
5375262685Sdelphij> </P
5376262685Sdelphij><P
5377262685Sdelphij>This request when given, toggles the present selection. This option is to be
5378262685Sdelphijused only in a multi valued menu. So to use this request the option O_ONEVALUE
5379262685Sdelphijmust be off. This option can be made off or on with set_menu_opts().</P
5380262685Sdelphij></LI
5381262685Sdelphij><LI
5382262685Sdelphij><P
5383262685Sdelphij> <SPAN
5384262685SdelphijCLASS="emphasis"
5385262685Sdelphij><I
5386262685SdelphijCLASS="EMPHASIS"
5387262685Sdelphij>Pattern Requests </I
5388262685Sdelphij></SPAN
5389262685Sdelphij></P
5390262685Sdelphij><P
5391262685Sdelphij>Every menu has an associated pattern buffer, which is used to find the nearest
5392262685Sdelphijmatch to the ascii characters entered by the user. Whenever ascii characters are
5393262685Sdelphijgiven to menu_driver, it puts in to the pattern buffer. It also tries to find
5394262685Sdelphijthe nearest match to the pattern in the items list and moves current selection
5395262685Sdelphijto that item. The request REQ_CLEAR_PATTERN clears the pattern buffer. The
5396262685Sdelphijrequest REQ_BACK_PATTERN deletes the previous character in the pattern buffer.
5397262685SdelphijIn case the pattern matches more than one item then the matched items can be
5398262685Sdelphijcycled through REQ_NEXT_MATCH and REQ_PREV_MATCH which move the current
5399262685Sdelphijselection to the next and previous matches respectively.</P
5400262685Sdelphij></LI
5401262685Sdelphij><LI
5402262685Sdelphij><P
5403262685Sdelphij> <SPAN
5404262685SdelphijCLASS="emphasis"
5405262685Sdelphij><I
5406262685SdelphijCLASS="EMPHASIS"
5407262685Sdelphij>Mouse Requests</I
5408262685Sdelphij></SPAN
5409262685Sdelphij></P
5410262685Sdelphij><P
5411262685Sdelphij>In case of KEY_MOUSE requests, according to the mouse position an action is
5412262685Sdelphijtaken accordingly. The action to be taken is explained in the man page as, </P
5413262685Sdelphij><PRE
5414262685SdelphijCLASS="PROGRAMLISTING"
5415262685Sdelphij><SPAN
5416262685SdelphijCLASS="emphasis"
5417262685Sdelphij><I
5418262685SdelphijCLASS="EMPHASIS"
5419262685Sdelphij>       If  the  second argument is the KEY_MOUSE special key, the
5420166124Srafan       associated mouse event is translated into one of the above
5421166124Srafan       pre-defined  requests.   Currently only clicks in the user
5422166124Srafan       window (e.g. inside the menu display area or  the  decora&shy;
5423166124Srafan       tion  window)  are handled. If you click above the display
5424166124Srafan       region of the menu, a REQ_SCR_ULINE is generated,  if  you
5425166124Srafan       doubleclick  a  REQ_SCR_UPAGE  is  generated  and  if  you
5426166124Srafan       tripleclick a REQ_FIRST_ITEM is generated.  If  you  click
5427166124Srafan       below  the  display region of the menu, a REQ_SCR_DLINE is
5428166124Srafan       generated, if you doubleclick a REQ_SCR_DPAGE is generated
5429166124Srafan       and  if  you  tripleclick a REQ_LAST_ITEM is generated. If
5430166124Srafan       you click at an item inside the display area of the  menu,
5431262685Sdelphij       the menu cursor is positioned to that item.</I
5432262685Sdelphij></SPAN
5433262685Sdelphij></PRE
5434262685Sdelphij></LI
5435262685Sdelphij></UL
5436262685Sdelphij><P
5437262685Sdelphij>Each of the above requests will be explained in the following lines with several
5438262685Sdelphijexamples whenever appropriate.</P
5439262685Sdelphij></DIV
5440262685Sdelphij><DIV
5441262685SdelphijCLASS="SECT2"
5442262685Sdelphij><HR><H3
5443262685SdelphijCLASS="SECT2"
5444262685Sdelphij><A
5445262685SdelphijNAME="MENUWINDOWS"
5446262685Sdelphij>17.4. Menu Windows</A
5447262685Sdelphij></H3
5448262685Sdelphij><P
5449262685Sdelphij>Every menu created is associated with a window and a sub window. The menu window
5450262685Sdelphijdisplays any title or border associated with the menu. The menu sub window
5451262685Sdelphijdisplays the menu items currently available for selection. But we didn't specify
5452262685Sdelphijany window or sub window in the simple example. When a window is not specified,
5453262685Sdelphijstdscr is taken as the main window, and then menu system calculates the sub
5454262685Sdelphijwindow size required for the display of items. Then items are displayed in the
5455262685Sdelphijcalculated sub window. So let's play with these windows and display a menu with
5456262685Sdelphija border and a title.</P
5457262685Sdelphij><DIV
5458262685SdelphijCLASS="EXAMPLE"
5459262685Sdelphij><A
5460262685SdelphijNAME="MMEWI"
5461262685Sdelphij></A
5462262685Sdelphij><P
5463262685Sdelphij><B
5464262685Sdelphij>Example 19.  Menu Windows Usage example </B
5465262685Sdelphij></P
5466262685Sdelphij><PRE
5467262685SdelphijCLASS="PROGRAMLISTING"
5468262685Sdelphij><SPAN
5469262685SdelphijCLASS="INLINEMEDIAOBJECT"
5470262685Sdelphij>#include &#60;menu.h&#62;
5471166124Srafan
5472166124Srafan#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
5473262685Sdelphij#define CTRLD 	4
5474166124Srafan
5475166124Srafanchar *choices[] = {
5476166124Srafan                        "Choice 1",
5477166124Srafan                        "Choice 2",
5478166124Srafan                        "Choice 3",
5479166124Srafan                        "Choice 4",
5480166124Srafan                        "Exit",
5481166124Srafan                        (char *)NULL,
5482166124Srafan                  };
5483166124Srafanvoid print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color);
5484166124Srafan
5485166124Srafanint main()
5486262685Sdelphij{	ITEM **my_items;
5487262685Sdelphij	int c;				
5488262685Sdelphij	MENU *my_menu;
5489166124Srafan        WINDOW *my_menu_win;
5490166124Srafan        int n_choices, i;
5491262685Sdelphij	
5492262685Sdelphij	/* Initialize curses */
5493262685Sdelphij	initscr();
5494262685Sdelphij	start_color();
5495166124Srafan        cbreak();
5496166124Srafan        noecho();
5497262685Sdelphij	keypad(stdscr, TRUE);
5498262685Sdelphij	init_pair(1, COLOR_RED, COLOR_BLACK);
5499166124Srafan
5500262685Sdelphij	/* Create items */
5501166124Srafan        n_choices = ARRAY_SIZE(choices);
5502166124Srafan        my_items = (ITEM **)calloc(n_choices, sizeof(ITEM *));
5503262685Sdelphij        for(i = 0; i &#60; n_choices; ++i)
5504166124Srafan                my_items[i] = new_item(choices[i], choices[i]);
5505166124Srafan
5506262685Sdelphij	/* Crate menu */
5507262685Sdelphij	my_menu = new_menu((ITEM **)my_items);
5508166124Srafan
5509262685Sdelphij	/* Create the window to be associated with the menu */
5510166124Srafan        my_menu_win = newwin(10, 40, 4, 4);
5511166124Srafan        keypad(my_menu_win, TRUE);
5512166124Srafan     
5513262685Sdelphij	/* Set main window and sub window */
5514166124Srafan        set_menu_win(my_menu, my_menu_win);
5515166124Srafan        set_menu_sub(my_menu, derwin(my_menu_win, 6, 38, 3, 1));
5516166124Srafan
5517262685Sdelphij	/* Set menu mark to the string " * " */
5518166124Srafan        set_menu_mark(my_menu, " * ");
5519166124Srafan
5520262685Sdelphij	/* Print a border around the main window and print a title */
5521166124Srafan        box(my_menu_win, 0, 0);
5522262685Sdelphij	print_in_middle(my_menu_win, 1, 0, 40, "My Menu", COLOR_PAIR(1));
5523262685Sdelphij	mvwaddch(my_menu_win, 2, 0, ACS_LTEE);
5524262685Sdelphij	mvwhline(my_menu_win, 2, 1, ACS_HLINE, 38);
5525262685Sdelphij	mvwaddch(my_menu_win, 2, 39, ACS_RTEE);
5526262685Sdelphij	mvprintw(LINES - 2, 0, "F1 to exit");
5527262685Sdelphij	refresh();
5528166124Srafan        
5529262685Sdelphij	/* Post the menu */
5530262685Sdelphij	post_menu(my_menu);
5531262685Sdelphij	wrefresh(my_menu_win);
5532166124Srafan
5533262685Sdelphij	while((c = wgetch(my_menu_win)) != KEY_F(1))
5534262685Sdelphij	{       switch(c)
5535262685Sdelphij	        {	case KEY_DOWN:
5536262685Sdelphij				menu_driver(my_menu, REQ_DOWN_ITEM);
5537262685Sdelphij				break;
5538262685Sdelphij			case KEY_UP:
5539262685Sdelphij				menu_driver(my_menu, REQ_UP_ITEM);
5540262685Sdelphij				break;
5541262685Sdelphij		}
5542166124Srafan                wrefresh(my_menu_win);
5543262685Sdelphij	}	
5544166124Srafan
5545262685Sdelphij	/* Unpost and free all the memory taken up */
5546166124Srafan        unpost_menu(my_menu);
5547166124Srafan        free_menu(my_menu);
5548262685Sdelphij        for(i = 0; i &#60; n_choices; ++i)
5549166124Srafan                free_item(my_items[i]);
5550262685Sdelphij	endwin();
5551166124Srafan}
5552166124Srafan
5553166124Srafanvoid print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color)
5554262685Sdelphij{	int length, x, y;
5555262685Sdelphij	float temp;
5556166124Srafan
5557262685Sdelphij	if(win == NULL)
5558262685Sdelphij		win = stdscr;
5559262685Sdelphij	getyx(win, y, x);
5560262685Sdelphij	if(startx != 0)
5561262685Sdelphij		x = startx;
5562262685Sdelphij	if(starty != 0)
5563262685Sdelphij		y = starty;
5564262685Sdelphij	if(width == 0)
5565262685Sdelphij		width = 80;
5566166124Srafan
5567262685Sdelphij	length = strlen(string);
5568262685Sdelphij	temp = (width - length)/ 2;
5569262685Sdelphij	x = startx + (int)temp;
5570262685Sdelphij	wattron(win, color);
5571262685Sdelphij	mvwprintw(win, y, x, "%s", string);
5572262685Sdelphij	wattroff(win, color);
5573262685Sdelphij	refresh();
5574262685Sdelphij}</SPAN
5575262685Sdelphij></PRE
5576262685Sdelphij></DIV
5577262685Sdelphij><P
5578262685Sdelphij>This example creates a menu with a title, border, a fancy line separating title
5579262685Sdelphijand the items. As you can see, in order to attach a window to a menu the
5580262685Sdelphijfunction set_menu_win() has to be used. Then we attach the sub window also. This
5581262685Sdelphijdisplays the items in the sub window.  You can also set the mark string which
5582262685Sdelphijgets displayed to the left of the selected item with set_menu_mark().</P
5583262685Sdelphij></DIV
5584262685Sdelphij><DIV
5585262685SdelphijCLASS="SECT2"
5586262685Sdelphij><HR><H3
5587262685SdelphijCLASS="SECT2"
5588262685Sdelphij><A
5589262685SdelphijNAME="SCROLLMENUS"
5590262685Sdelphij>17.5. Scrolling Menus</A
5591262685Sdelphij></H3
5592262685Sdelphij><P
5593262685Sdelphij>If the sub window given for a window is not big enough to show all the items,
5594262685Sdelphijthen the menu will be scrollable. When you are on the last item in the present
5595262685Sdelphijlist, if you send REQ_DOWN_ITEM, it gets translated into REQ_SCR_DLINE and the
5596262685Sdelphijmenu scrolls by one item.  You can manually give REQ_SCR_ operations to do
5597262685Sdelphijscrolling. Let's see how it can be done.</P
5598262685Sdelphij><DIV
5599262685SdelphijCLASS="EXAMPLE"
5600262685Sdelphij><A
5601262685SdelphijNAME="MMESC"
5602262685Sdelphij></A
5603262685Sdelphij><P
5604262685Sdelphij><B
5605262685Sdelphij>Example 20.  Scrolling Menus example </B
5606262685Sdelphij></P
5607262685Sdelphij><PRE
5608262685SdelphijCLASS="PROGRAMLISTING"
5609262685Sdelphij><SPAN
5610262685SdelphijCLASS="INLINEMEDIAOBJECT"
5611262685Sdelphij>#include &#60;curses.h&#62;
5612262685Sdelphij#include &#60;menu.h&#62;
5613166124Srafan
5614166124Srafan#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
5615262685Sdelphij#define CTRLD 	4
5616166124Srafan
5617166124Srafanchar *choices[] = {
5618166124Srafan                        "Choice 1",
5619166124Srafan                        "Choice 2",
5620166124Srafan                        "Choice 3",
5621166124Srafan                        "Choice 4",
5622262685Sdelphij			"Choice 5",
5623262685Sdelphij			"Choice 6",
5624262685Sdelphij			"Choice 7",
5625262685Sdelphij			"Choice 8",
5626262685Sdelphij			"Choice 9",
5627262685Sdelphij			"Choice 10",
5628166124Srafan                        "Exit",
5629166124Srafan                        (char *)NULL,
5630166124Srafan                  };
5631166124Srafanvoid print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color);
5632166124Srafan
5633166124Srafanint main()
5634262685Sdelphij{	ITEM **my_items;
5635262685Sdelphij	int c;				
5636262685Sdelphij	MENU *my_menu;
5637166124Srafan        WINDOW *my_menu_win;
5638166124Srafan        int n_choices, i;
5639262685Sdelphij	
5640262685Sdelphij	/* Initialize curses */
5641262685Sdelphij	initscr();
5642262685Sdelphij	start_color();
5643166124Srafan        cbreak();
5644166124Srafan        noecho();
5645262685Sdelphij	keypad(stdscr, TRUE);
5646262685Sdelphij	init_pair(1, COLOR_RED, COLOR_BLACK);
5647262685Sdelphij	init_pair(2, COLOR_CYAN, COLOR_BLACK);
5648166124Srafan
5649262685Sdelphij	/* Create items */
5650166124Srafan        n_choices = ARRAY_SIZE(choices);
5651166124Srafan        my_items = (ITEM **)calloc(n_choices, sizeof(ITEM *));
5652262685Sdelphij        for(i = 0; i &#60; n_choices; ++i)
5653166124Srafan                my_items[i] = new_item(choices[i], choices[i]);
5654166124Srafan
5655262685Sdelphij	/* Crate menu */
5656262685Sdelphij	my_menu = new_menu((ITEM **)my_items);
5657166124Srafan
5658262685Sdelphij	/* Create the window to be associated with the menu */
5659166124Srafan        my_menu_win = newwin(10, 40, 4, 4);
5660166124Srafan        keypad(my_menu_win, TRUE);
5661166124Srafan     
5662262685Sdelphij	/* Set main window and sub window */
5663166124Srafan        set_menu_win(my_menu, my_menu_win);
5664166124Srafan        set_menu_sub(my_menu, derwin(my_menu_win, 6, 38, 3, 1));
5665262685Sdelphij	set_menu_format(my_menu, 5, 1);
5666262685Sdelphij			
5667262685Sdelphij	/* Set menu mark to the string " * " */
5668166124Srafan        set_menu_mark(my_menu, " * ");
5669166124Srafan
5670262685Sdelphij	/* Print a border around the main window and print a title */
5671166124Srafan        box(my_menu_win, 0, 0);
5672262685Sdelphij	print_in_middle(my_menu_win, 1, 0, 40, "My Menu", COLOR_PAIR(1));
5673262685Sdelphij	mvwaddch(my_menu_win, 2, 0, ACS_LTEE);
5674262685Sdelphij	mvwhline(my_menu_win, 2, 1, ACS_HLINE, 38);
5675262685Sdelphij	mvwaddch(my_menu_win, 2, 39, ACS_RTEE);
5676166124Srafan        
5677262685Sdelphij	/* Post the menu */
5678262685Sdelphij	post_menu(my_menu);
5679262685Sdelphij	wrefresh(my_menu_win);
5680262685Sdelphij	
5681262685Sdelphij	attron(COLOR_PAIR(2));
5682262685Sdelphij	mvprintw(LINES - 2, 0, "Use PageUp and PageDown to scoll down or up a page of items");
5683262685Sdelphij	mvprintw(LINES - 1, 0, "Arrow Keys to navigate (F1 to Exit)");
5684262685Sdelphij	attroff(COLOR_PAIR(2));
5685262685Sdelphij	refresh();
5686166124Srafan
5687262685Sdelphij	while((c = wgetch(my_menu_win)) != KEY_F(1))
5688262685Sdelphij	{       switch(c)
5689262685Sdelphij	        {	case KEY_DOWN:
5690262685Sdelphij				menu_driver(my_menu, REQ_DOWN_ITEM);
5691262685Sdelphij				break;
5692262685Sdelphij			case KEY_UP:
5693262685Sdelphij				menu_driver(my_menu, REQ_UP_ITEM);
5694262685Sdelphij				break;
5695262685Sdelphij			case KEY_NPAGE:
5696262685Sdelphij				menu_driver(my_menu, REQ_SCR_DPAGE);
5697262685Sdelphij				break;
5698262685Sdelphij			case KEY_PPAGE:
5699262685Sdelphij				menu_driver(my_menu, REQ_SCR_UPAGE);
5700262685Sdelphij				break;
5701262685Sdelphij		}
5702166124Srafan                wrefresh(my_menu_win);
5703262685Sdelphij	}	
5704166124Srafan
5705262685Sdelphij	/* Unpost and free all the memory taken up */
5706166124Srafan        unpost_menu(my_menu);
5707166124Srafan        free_menu(my_menu);
5708262685Sdelphij        for(i = 0; i &#60; n_choices; ++i)
5709166124Srafan                free_item(my_items[i]);
5710262685Sdelphij	endwin();
5711166124Srafan}
5712166124Srafan
5713166124Srafanvoid print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color)
5714262685Sdelphij{	int length, x, y;
5715262685Sdelphij	float temp;
5716166124Srafan
5717262685Sdelphij	if(win == NULL)
5718262685Sdelphij		win = stdscr;
5719262685Sdelphij	getyx(win, y, x);
5720262685Sdelphij	if(startx != 0)
5721262685Sdelphij		x = startx;
5722262685Sdelphij	if(starty != 0)
5723262685Sdelphij		y = starty;
5724262685Sdelphij	if(width == 0)
5725262685Sdelphij		width = 80;
5726166124Srafan
5727262685Sdelphij	length = strlen(string);
5728262685Sdelphij	temp = (width - length)/ 2;
5729262685Sdelphij	x = startx + (int)temp;
5730262685Sdelphij	wattron(win, color);
5731262685Sdelphij	mvwprintw(win, y, x, "%s", string);
5732262685Sdelphij	wattroff(win, color);
5733262685Sdelphij	refresh();
5734262685Sdelphij}</SPAN
5735262685Sdelphij></PRE
5736262685Sdelphij></DIV
5737262685Sdelphij><P
5738262685Sdelphij>This program is self-explanatory. In this example the number of choices has been
5739262685Sdelphijincreased to ten, which is larger than our sub window size which can hold 6
5740262685Sdelphijitems.  This message has to be explicitly conveyed to the menu system with the
5741262685Sdelphijfunction set_menu_format(). In here we specify the number of rows and columns we
5742262685Sdelphijwant to be displayed for a single page. We can specify any number of items to be
5743262685Sdelphijshown, in the rows variables, if it is less than the height of the sub window.
5744262685SdelphijIf the key pressed by the user is a PAGE UP or PAGE DOWN, the menu is scrolled a
5745262685Sdelphijpage due to the requests (REQ_SCR_DPAGE and REQ_SCR_UPAGE) given to
5746262685Sdelphijmenu_driver().</P
5747262685Sdelphij></DIV
5748262685Sdelphij><DIV
5749262685SdelphijCLASS="SECT2"
5750262685Sdelphij><HR><H3
5751262685SdelphijCLASS="SECT2"
5752262685Sdelphij><A
5753262685SdelphijNAME="MULTICOLUMN"
5754262685Sdelphij>17.6. Multi Columnar Menus</A
5755262685Sdelphij></H3
5756262685Sdelphij><P
5757262685Sdelphij>In the above example you have seen how to use the function set_menu_format(). I
5758262685Sdelphijdidn't mention what the cols variable (third parameter) does. Well, If your sub
5759262685Sdelphijwindow is wide enough, you can opt to display more than one item per row. This
5760262685Sdelphijcan be specified in the cols variable. To make things simpler, the following
5761262685Sdelphijexample doesn't show descriptions for the items.</P
5762262685Sdelphij><DIV
5763262685SdelphijCLASS="EXAMPLE"
5764262685Sdelphij><A
5765262685SdelphijNAME="MMEMUCO"
5766262685Sdelphij></A
5767262685Sdelphij><P
5768262685Sdelphij><B
5769262685Sdelphij>Example 21.  Milt Columnar Menus Example </B
5770262685Sdelphij></P
5771262685Sdelphij><PRE
5772262685SdelphijCLASS="PROGRAMLISTING"
5773262685Sdelphij><SPAN
5774262685SdelphijCLASS="INLINEMEDIAOBJECT"
5775262685Sdelphij>#include &#60;curses.h&#62;
5776262685Sdelphij#include &#60;menu.h&#62;
5777166124Srafan
5778166124Srafan#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
5779262685Sdelphij#define CTRLD 	4
5780166124Srafan
5781166124Srafanchar *choices[] = {
5782166124Srafan                        "Choice 1", "Choice 2", "Choice 3", "Choice 4", "Choice 5",
5783262685Sdelphij			"Choice 6", "Choice 7", "Choice 8", "Choice 9", "Choice 10",
5784262685Sdelphij			"Choice 11", "Choice 12", "Choice 13", "Choice 14", "Choice 15",
5785262685Sdelphij			"Choice 16", "Choice 17", "Choice 18", "Choice 19", "Choice 20",
5786166124Srafan                        "Exit",
5787166124Srafan                        (char *)NULL,
5788166124Srafan                  };
5789166124Srafan
5790166124Srafanint main()
5791262685Sdelphij{	ITEM **my_items;
5792262685Sdelphij	int c;				
5793262685Sdelphij	MENU *my_menu;
5794166124Srafan        WINDOW *my_menu_win;
5795166124Srafan        int n_choices, i;
5796262685Sdelphij	
5797262685Sdelphij	/* Initialize curses */
5798262685Sdelphij	initscr();
5799262685Sdelphij	start_color();
5800166124Srafan        cbreak();
5801166124Srafan        noecho();
5802262685Sdelphij	keypad(stdscr, TRUE);
5803262685Sdelphij	init_pair(1, COLOR_RED, COLOR_BLACK);
5804262685Sdelphij	init_pair(2, COLOR_CYAN, COLOR_BLACK);
5805166124Srafan
5806262685Sdelphij	/* Create items */
5807166124Srafan        n_choices = ARRAY_SIZE(choices);
5808166124Srafan        my_items = (ITEM **)calloc(n_choices, sizeof(ITEM *));
5809262685Sdelphij        for(i = 0; i &#60; n_choices; ++i)
5810166124Srafan                my_items[i] = new_item(choices[i], choices[i]);
5811166124Srafan
5812262685Sdelphij	/* Crate menu */
5813262685Sdelphij	my_menu = new_menu((ITEM **)my_items);
5814166124Srafan
5815262685Sdelphij	/* Set menu option not to show the description */
5816262685Sdelphij	menu_opts_off(my_menu, O_SHOWDESC);
5817166124Srafan
5818262685Sdelphij	/* Create the window to be associated with the menu */
5819166124Srafan        my_menu_win = newwin(10, 70, 4, 4);
5820166124Srafan        keypad(my_menu_win, TRUE);
5821166124Srafan     
5822262685Sdelphij	/* Set main window and sub window */
5823166124Srafan        set_menu_win(my_menu, my_menu_win);
5824166124Srafan        set_menu_sub(my_menu, derwin(my_menu_win, 6, 68, 3, 1));
5825262685Sdelphij	set_menu_format(my_menu, 5, 3);
5826262685Sdelphij	set_menu_mark(my_menu, " * ");
5827166124Srafan
5828262685Sdelphij	/* Print a border around the main window and print a title */
5829166124Srafan        box(my_menu_win, 0, 0);
5830262685Sdelphij	
5831262685Sdelphij	attron(COLOR_PAIR(2));
5832262685Sdelphij	mvprintw(LINES - 3, 0, "Use PageUp and PageDown to scroll");
5833262685Sdelphij	mvprintw(LINES - 2, 0, "Use Arrow Keys to navigate (F1 to Exit)");
5834262685Sdelphij	attroff(COLOR_PAIR(2));
5835262685Sdelphij	refresh();
5836166124Srafan
5837262685Sdelphij	/* Post the menu */
5838262685Sdelphij	post_menu(my_menu);
5839262685Sdelphij	wrefresh(my_menu_win);
5840262685Sdelphij	
5841262685Sdelphij	while((c = wgetch(my_menu_win)) != KEY_F(1))
5842262685Sdelphij	{       switch(c)
5843262685Sdelphij	        {	case KEY_DOWN:
5844262685Sdelphij				menu_driver(my_menu, REQ_DOWN_ITEM);
5845262685Sdelphij				break;
5846262685Sdelphij			case KEY_UP:
5847262685Sdelphij				menu_driver(my_menu, REQ_UP_ITEM);
5848262685Sdelphij				break;
5849262685Sdelphij			case KEY_LEFT:
5850262685Sdelphij				menu_driver(my_menu, REQ_LEFT_ITEM);
5851262685Sdelphij				break;
5852262685Sdelphij			case KEY_RIGHT:
5853262685Sdelphij				menu_driver(my_menu, REQ_RIGHT_ITEM);
5854262685Sdelphij				break;
5855262685Sdelphij			case KEY_NPAGE:
5856262685Sdelphij				menu_driver(my_menu, REQ_SCR_DPAGE);
5857262685Sdelphij				break;
5858262685Sdelphij			case KEY_PPAGE:
5859262685Sdelphij				menu_driver(my_menu, REQ_SCR_UPAGE);
5860262685Sdelphij				break;
5861262685Sdelphij		}
5862166124Srafan                wrefresh(my_menu_win);
5863262685Sdelphij	}	
5864166124Srafan
5865262685Sdelphij	/* Unpost and free all the memory taken up */
5866166124Srafan        unpost_menu(my_menu);
5867166124Srafan        free_menu(my_menu);
5868262685Sdelphij        for(i = 0; i &#60; n_choices; ++i)
5869166124Srafan                free_item(my_items[i]);
5870262685Sdelphij	endwin();
5871262685Sdelphij}</SPAN
5872262685Sdelphij></PRE
5873262685Sdelphij></DIV
5874262685Sdelphij><P
5875262685Sdelphij>Watch the function call to set_menu_format(). It specifies the number of columns
5876262685Sdelphijto be 3, thus displaying 3 items per row. We have also switched off the showing
5877262685Sdelphijdescriptions with the function menu_opts_off(). There are couple of functions
5878262685Sdelphijset_menu_opts(),  menu_opts_on() and menu_opts() which can be used to manipulate
5879262685Sdelphijmenu options. The following menu options can be specified.</P
5880262685Sdelphij><PRE
5881262685SdelphijCLASS="PROGRAMLISTING"
5882262685Sdelphij>       O_ONEVALUE
5883166124Srafan            Only one item can be selected for this menu.
5884166124Srafan
5885166124Srafan       O_SHOWDESC
5886166124Srafan            Display  the  item  descriptions  when  the  menu  is
5887166124Srafan            posted.
5888166124Srafan
5889166124Srafan       O_ROWMAJOR
5890166124Srafan            Display the menu in row-major order.
5891166124Srafan
5892166124Srafan       O_IGNORECASE
5893166124Srafan            Ignore the case when pattern-matching.
5894166124Srafan
5895166124Srafan       O_SHOWMATCH
5896166124Srafan            Move the cursor to within the item  name  while  pat&shy;
5897166124Srafan            tern-matching.
5898166124Srafan
5899166124Srafan       O_NONCYCLIC
5900166124Srafan            Don't   wrap   around  next-item  and  previous-item,
5901262685Sdelphij            requests to the other end of the menu.</PRE
5902262685Sdelphij><P
5903262685Sdelphij>All options are on by default. You can switch specific attributes on or off with
5904262685Sdelphijmenu_opts_on() and menu_opts_off() functions. You can also use set_menu_opts()
5905262685Sdelphijto directly specify the options. The argument to this function should be a OR ed
5906262685Sdelphijvalue of some of those above constants. The function menu_opts() can be used to
5907262685Sdelphijfind out a menu's present options. </P
5908262685Sdelphij></DIV
5909262685Sdelphij><DIV
5910262685SdelphijCLASS="SECT2"
5911262685Sdelphij><HR><H3
5912262685SdelphijCLASS="SECT2"
5913262685Sdelphij><A
5914262685SdelphijNAME="MULTIVALUEMENUS"
5915262685Sdelphij>17.7. Multi Valued Menus</A
5916262685Sdelphij></H3
5917262685Sdelphij><P
5918262685Sdelphij>You might be wondering what if you switch off the option O_ONEVALUE. Then the
5919262685Sdelphijmenu becomes multi-valued. That means you can select more than one item. This
5920262685Sdelphijbrings us to the request REQ_TOGGLE_ITEM. Let's see it in action.</P
5921262685Sdelphij><DIV
5922262685SdelphijCLASS="EXAMPLE"
5923262685Sdelphij><A
5924262685SdelphijNAME="MMETO"
5925262685Sdelphij></A
5926262685Sdelphij><P
5927262685Sdelphij><B
5928262685Sdelphij>Example 22.  Multi Valued Menus example </B
5929262685Sdelphij></P
5930262685Sdelphij><PRE
5931262685SdelphijCLASS="PROGRAMLISTING"
5932262685Sdelphij><SPAN
5933262685SdelphijCLASS="INLINEMEDIAOBJECT"
5934262685Sdelphij>#include &#60;curses.h&#62;
5935262685Sdelphij#include &#60;menu.h&#62;
5936166124Srafan
5937166124Srafan#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
5938262685Sdelphij#define CTRLD 	4
5939166124Srafan
5940166124Srafanchar *choices[] = {
5941166124Srafan                        "Choice 1",
5942166124Srafan                        "Choice 2",
5943166124Srafan                        "Choice 3",
5944166124Srafan                        "Choice 4",
5945262685Sdelphij			"Choice 5",
5946262685Sdelphij			"Choice 6",
5947262685Sdelphij			"Choice 7",
5948166124Srafan                        "Exit",
5949166124Srafan                  };
5950166124Srafan
5951166124Srafanint main()
5952262685Sdelphij{	ITEM **my_items;
5953262685Sdelphij	int c;				
5954262685Sdelphij	MENU *my_menu;
5955166124Srafan        int n_choices, i;
5956262685Sdelphij	ITEM *cur_item;
5957262685Sdelphij	
5958262685Sdelphij	/* Initialize curses */	
5959262685Sdelphij	initscr();
5960166124Srafan        cbreak();
5961166124Srafan        noecho();
5962262685Sdelphij	keypad(stdscr, TRUE);
5963166124Srafan
5964262685Sdelphij	/* Initialize items */
5965166124Srafan        n_choices = ARRAY_SIZE(choices);
5966166124Srafan        my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *));
5967262685Sdelphij        for(i = 0; i &#60; n_choices; ++i)
5968166124Srafan                my_items[i] = new_item(choices[i], choices[i]);
5969262685Sdelphij	my_items[n_choices] = (ITEM *)NULL;
5970166124Srafan
5971262685Sdelphij	my_menu = new_menu((ITEM **)my_items);
5972166124Srafan
5973262685Sdelphij	/* Make the menu multi valued */
5974262685Sdelphij	menu_opts_off(my_menu, O_ONEVALUE);
5975166124Srafan
5976262685Sdelphij	mvprintw(LINES - 3, 0, "Use &#60;SPACE&#62; to select or unselect an item.");
5977262685Sdelphij	mvprintw(LINES - 2, 0, "&#60;ENTER&#62; to see presently selected items(F1 to Exit)");
5978262685Sdelphij	post_menu(my_menu);
5979262685Sdelphij	refresh();
5980166124Srafan
5981262685Sdelphij	while((c = getch()) != KEY_F(1))
5982262685Sdelphij	{       switch(c)
5983262685Sdelphij	        {	case KEY_DOWN:
5984262685Sdelphij				menu_driver(my_menu, REQ_DOWN_ITEM);
5985262685Sdelphij				break;
5986262685Sdelphij			case KEY_UP:
5987262685Sdelphij				menu_driver(my_menu, REQ_UP_ITEM);
5988262685Sdelphij				break;
5989262685Sdelphij			case ' ':
5990262685Sdelphij				menu_driver(my_menu, REQ_TOGGLE_ITEM);
5991262685Sdelphij				break;
5992262685Sdelphij			case 10:	/* Enter */
5993262685Sdelphij			{	char temp[200];
5994262685Sdelphij				ITEM **items;
5995166124Srafan
5996262685Sdelphij				items = menu_items(my_menu);
5997262685Sdelphij				temp[0] = '\0';
5998262685Sdelphij				for(i = 0; i &#60; item_count(my_menu); ++i)
5999262685Sdelphij					if(item_value(items[i]) == TRUE)
6000262685Sdelphij					{	strcat(temp, item_name(items[i]));
6001262685Sdelphij						strcat(temp, " ");
6002262685Sdelphij					}
6003262685Sdelphij				move(20, 0);
6004262685Sdelphij				clrtoeol();
6005262685Sdelphij				mvprintw(20, 0, temp);
6006262685Sdelphij				refresh();
6007262685Sdelphij			}
6008262685Sdelphij			break;
6009262685Sdelphij		}
6010262685Sdelphij	}	
6011166124Srafan
6012262685Sdelphij	free_item(my_items[0]);
6013166124Srafan        free_item(my_items[1]);
6014262685Sdelphij	free_menu(my_menu);
6015262685Sdelphij	endwin();
6016166124Srafan}
6017262685Sdelphij	</SPAN
6018262685Sdelphij></PRE
6019262685Sdelphij></DIV
6020262685Sdelphij><P
6021262685Sdelphij>Whew, A lot of new functions. Let's take them one after another. Firstly, the
6022262685SdelphijREQ_TOGGLE_ITEM.  In a multi-valued menu, the user should be allowed to select
6023262685Sdelphijor un select more than one item. The request REQ_TOGGLE_ITEM toggles the present
6024262685Sdelphijselection. In this case when space is pressed REQ_TOGGLE_ITEM request is sent to
6025262685Sdelphijmenu_driver to achieve the result.</P
6026262685Sdelphij><P
6027262685Sdelphij>Now when the user presses &lt;ENTER&gt; we show the items he presently selected.
6028262685SdelphijFirst we find out the items associated with the menu using the function
6029262685Sdelphijmenu_items(). Then we loop through the items to find out if the item is selected
6030262685Sdelphijor not. The function item_value() returns TRUE if an item is selected. The
6031262685Sdelphijfunction item_count() returns the number of items in the menu. The item name can
6032262685Sdelphijbe found with item_name(). You can also find the description associated with an
6033262685Sdelphijitem using item_description().</P
6034262685Sdelphij></DIV
6035262685Sdelphij><DIV
6036262685SdelphijCLASS="SECT2"
6037262685Sdelphij><HR><H3
6038262685SdelphijCLASS="SECT2"
6039262685Sdelphij><A
6040262685SdelphijNAME="MENUOPT"
6041262685Sdelphij>17.8. Menu Options</A
6042262685Sdelphij></H3
6043262685Sdelphij><P
6044262685Sdelphij>Well, by this time you must be itching for some difference in your menu, with
6045262685Sdelphijlots of functionality. I know. You want Colors !!!. You want to create nice
6046262685Sdelphijmenus similar to those text mode <A
6047262685SdelphijHREF="http://www.jersey.net/~debinjoe/games/"
6048262685SdelphijTARGET="_top"
6049262685Sdelphij>dos games</A
6050262685Sdelphij>. The functions
6051262685Sdelphijset_menu_fore() and set_menu_back() can be used to change the attribute of the
6052262685Sdelphijselected item and unselected item. The names are misleading. They don't change
6053262685Sdelphijmenu's foreground or background which would have been useless. </P
6054262685Sdelphij><P
6055262685Sdelphij>The function set_menu_grey() can be used to set the display attribute for the
6056262685Sdelphijnon-selectable items in the menu. This brings us to the interesting option for
6057262685Sdelphijan item the one and only O_SELECTABLE. We can turn it off by the function
6058262685Sdelphijitem_opts_off() and after that that item is not selectable. It's like a grayed
6059262685Sdelphijitem in those fancy windows menus. Let's put these concepts in practice with
6060262685Sdelphijthis example</P
6061262685Sdelphij><DIV
6062262685SdelphijCLASS="EXAMPLE"
6063262685Sdelphij><A
6064262685SdelphijNAME="MMEAT"
6065262685Sdelphij></A
6066262685Sdelphij><P
6067262685Sdelphij><B
6068262685Sdelphij>Example 23.  Menu Options example </B
6069262685Sdelphij></P
6070262685Sdelphij><PRE
6071262685SdelphijCLASS="PROGRAMLISTING"
6072262685Sdelphij><SPAN
6073262685SdelphijCLASS="INLINEMEDIAOBJECT"
6074262685Sdelphij>#include &#60;menu.h&#62;
6075166124Srafan
6076166124Srafan#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
6077262685Sdelphij#define CTRLD 	4
6078166124Srafan
6079166124Srafanchar *choices[] = {
6080166124Srafan                        "Choice 1",
6081166124Srafan                        "Choice 2",
6082166124Srafan                        "Choice 3",
6083166124Srafan                        "Choice 4",
6084262685Sdelphij			"Choice 5",
6085262685Sdelphij			"Choice 6",
6086262685Sdelphij			"Choice 7",
6087166124Srafan                        "Exit",
6088166124Srafan                  };
6089166124Srafan
6090166124Srafanint main()
6091262685Sdelphij{	ITEM **my_items;
6092262685Sdelphij	int c;				
6093262685Sdelphij	MENU *my_menu;
6094166124Srafan        int n_choices, i;
6095262685Sdelphij	ITEM *cur_item;
6096262685Sdelphij	
6097262685Sdelphij	/* Initialize curses */	
6098262685Sdelphij	initscr();
6099262685Sdelphij	start_color();
6100166124Srafan        cbreak();
6101166124Srafan        noecho();
6102262685Sdelphij	keypad(stdscr, TRUE);
6103262685Sdelphij	init_pair(1, COLOR_RED, COLOR_BLACK);
6104262685Sdelphij	init_pair(2, COLOR_GREEN, COLOR_BLACK);
6105262685Sdelphij	init_pair(3, COLOR_MAGENTA, COLOR_BLACK);
6106166124Srafan
6107262685Sdelphij	/* Initialize items */
6108166124Srafan        n_choices = ARRAY_SIZE(choices);
6109166124Srafan        my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *));
6110262685Sdelphij        for(i = 0; i &#60; n_choices; ++i)
6111166124Srafan                my_items[i] = new_item(choices[i], choices[i]);
6112262685Sdelphij	my_items[n_choices] = (ITEM *)NULL;
6113262685Sdelphij	item_opts_off(my_items[3], O_SELECTABLE);
6114262685Sdelphij	item_opts_off(my_items[6], O_SELECTABLE);
6115166124Srafan
6116262685Sdelphij	/* Create menu */
6117262685Sdelphij	my_menu = new_menu((ITEM **)my_items);
6118166124Srafan
6119262685Sdelphij	/* Set fore ground and back ground of the menu */
6120262685Sdelphij	set_menu_fore(my_menu, COLOR_PAIR(1) | A_REVERSE);
6121262685Sdelphij	set_menu_back(my_menu, COLOR_PAIR(2));
6122262685Sdelphij	set_menu_grey(my_menu, COLOR_PAIR(3));
6123166124Srafan
6124262685Sdelphij	/* Post the menu */
6125262685Sdelphij	mvprintw(LINES - 3, 0, "Press &#60;ENTER&#62; to see the option selected");
6126262685Sdelphij	mvprintw(LINES - 2, 0, "Up and Down arrow keys to naviage (F1 to Exit)");
6127262685Sdelphij	post_menu(my_menu);
6128262685Sdelphij	refresh();
6129166124Srafan
6130262685Sdelphij	while((c = getch()) != KEY_F(1))
6131262685Sdelphij	{       switch(c)
6132262685Sdelphij	        {	case KEY_DOWN:
6133262685Sdelphij				menu_driver(my_menu, REQ_DOWN_ITEM);
6134262685Sdelphij				break;
6135262685Sdelphij			case KEY_UP:
6136262685Sdelphij				menu_driver(my_menu, REQ_UP_ITEM);
6137262685Sdelphij				break;
6138262685Sdelphij			case 10: /* Enter */
6139262685Sdelphij				move(20, 0);
6140262685Sdelphij				clrtoeol();
6141262685Sdelphij				mvprintw(20, 0, "Item selected is : %s", 
6142262685Sdelphij						item_name(current_item(my_menu)));
6143262685Sdelphij				pos_menu_cursor(my_menu);
6144262685Sdelphij				break;
6145262685Sdelphij		}
6146262685Sdelphij	}	
6147262685Sdelphij	unpost_menu(my_menu);
6148262685Sdelphij	for(i = 0; i &#60; n_choices; ++i)
6149262685Sdelphij		free_item(my_items[i]);
6150262685Sdelphij	free_menu(my_menu);
6151262685Sdelphij	endwin();
6152166124Srafan}
6153262685Sdelphij	</SPAN
6154262685Sdelphij></PRE
6155262685Sdelphij></DIV
6156262685Sdelphij></DIV
6157262685Sdelphij><DIV
6158262685SdelphijCLASS="SECT2"
6159262685Sdelphij><HR><H3
6160262685SdelphijCLASS="SECT2"
6161262685Sdelphij><A
6162262685SdelphijNAME="MENUUSERPTR"
6163262685Sdelphij>17.9. The useful User Pointer</A
6164262685Sdelphij></H3
6165262685Sdelphij><P
6166262685Sdelphij>We can associate a user pointer with each item in the menu. It works the same
6167262685Sdelphijway as user pointer in panels. It's not touched by menu system. You can store
6168262685Sdelphijany thing you like in that. I usually use it to store the function to be
6169262685Sdelphijexecuted when the menu option is chosen (It's selected and may be the user
6170262685Sdelphijpressed &lt;ENTER&gt;);</P
6171262685Sdelphij><DIV
6172262685SdelphijCLASS="EXAMPLE"
6173262685Sdelphij><A
6174262685SdelphijNAME="MMEUS"
6175262685Sdelphij></A
6176262685Sdelphij><P
6177262685Sdelphij><B
6178262685Sdelphij>Example 24.  Menu User Pointer Usage </B
6179262685Sdelphij></P
6180262685Sdelphij><PRE
6181262685SdelphijCLASS="PROGRAMLISTING"
6182262685Sdelphij><SPAN
6183262685SdelphijCLASS="INLINEMEDIAOBJECT"
6184262685Sdelphij>#include &#60;curses.h&#62;
6185262685Sdelphij#include &#60;menu.h&#62;
6186166124Srafan
6187166124Srafan#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
6188262685Sdelphij#define CTRLD 	4
6189166124Srafan
6190166124Srafanchar *choices[] = {
6191166124Srafan                        "Choice 1",
6192166124Srafan                        "Choice 2",
6193166124Srafan                        "Choice 3",
6194166124Srafan                        "Choice 4",
6195262685Sdelphij			"Choice 5",
6196262685Sdelphij			"Choice 6",
6197262685Sdelphij			"Choice 7",
6198166124Srafan                        "Exit",
6199166124Srafan                  };
6200166124Srafanvoid func(char *name);
6201166124Srafan
6202166124Srafanint main()
6203262685Sdelphij{	ITEM **my_items;
6204262685Sdelphij	int c;				
6205262685Sdelphij	MENU *my_menu;
6206166124Srafan        int n_choices, i;
6207262685Sdelphij	ITEM *cur_item;
6208262685Sdelphij	
6209262685Sdelphij	/* Initialize curses */	
6210262685Sdelphij	initscr();
6211262685Sdelphij	start_color();
6212166124Srafan        cbreak();
6213166124Srafan        noecho();
6214262685Sdelphij	keypad(stdscr, TRUE);
6215262685Sdelphij	init_pair(1, COLOR_RED, COLOR_BLACK);
6216262685Sdelphij	init_pair(2, COLOR_GREEN, COLOR_BLACK);
6217262685Sdelphij	init_pair(3, COLOR_MAGENTA, COLOR_BLACK);
6218166124Srafan
6219262685Sdelphij	/* Initialize items */
6220166124Srafan        n_choices = ARRAY_SIZE(choices);
6221166124Srafan        my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *));
6222262685Sdelphij        for(i = 0; i &#60; n_choices; ++i)
6223262685Sdelphij	{       my_items[i] = new_item(choices[i], choices[i]);
6224262685Sdelphij		/* Set the user pointer */
6225262685Sdelphij		set_item_userptr(my_items[i], func);
6226262685Sdelphij	}
6227262685Sdelphij	my_items[n_choices] = (ITEM *)NULL;
6228166124Srafan
6229262685Sdelphij	/* Create menu */
6230262685Sdelphij	my_menu = new_menu((ITEM **)my_items);
6231166124Srafan
6232262685Sdelphij	/* Post the menu */
6233262685Sdelphij	mvprintw(LINES - 3, 0, "Press &#60;ENTER&#62; to see the option selected");
6234262685Sdelphij	mvprintw(LINES - 2, 0, "Up and Down arrow keys to naviage (F1 to Exit)");
6235262685Sdelphij	post_menu(my_menu);
6236262685Sdelphij	refresh();
6237166124Srafan
6238262685Sdelphij	while((c = getch()) != KEY_F(1))
6239262685Sdelphij	{       switch(c)
6240262685Sdelphij	        {	case KEY_DOWN:
6241262685Sdelphij				menu_driver(my_menu, REQ_DOWN_ITEM);
6242262685Sdelphij				break;
6243262685Sdelphij			case KEY_UP:
6244262685Sdelphij				menu_driver(my_menu, REQ_UP_ITEM);
6245262685Sdelphij				break;
6246262685Sdelphij			case 10: /* Enter */
6247262685Sdelphij			{	ITEM *cur;
6248262685Sdelphij				void (*p)(char *);
6249166124Srafan
6250262685Sdelphij				cur = current_item(my_menu);
6251262685Sdelphij				p = item_userptr(cur);
6252262685Sdelphij				p((char *)item_name(cur));
6253262685Sdelphij				pos_menu_cursor(my_menu);
6254262685Sdelphij				break;
6255262685Sdelphij			}
6256262685Sdelphij			break;
6257262685Sdelphij		}
6258262685Sdelphij	}	
6259262685Sdelphij	unpost_menu(my_menu);
6260262685Sdelphij	for(i = 0; i &#60; n_choices; ++i)
6261262685Sdelphij		free_item(my_items[i]);
6262262685Sdelphij	free_menu(my_menu);
6263262685Sdelphij	endwin();
6264166124Srafan}
6265166124Srafan
6266166124Srafanvoid func(char *name)
6267262685Sdelphij{	move(20, 0);
6268262685Sdelphij	clrtoeol();
6269262685Sdelphij	mvprintw(20, 0, "Item selected is : %s", name);
6270262685Sdelphij}	</SPAN
6271262685Sdelphij></PRE
6272262685Sdelphij></DIV
6273262685Sdelphij></DIV
6274262685Sdelphij></DIV
6275262685Sdelphij><DIV
6276262685SdelphijCLASS="SECT1"
6277262685Sdelphij><HR><H2
6278262685SdelphijCLASS="SECT1"
6279262685Sdelphij><A
6280262685SdelphijNAME="FORMS"
6281262685Sdelphij>18. Forms Library</A
6282262685Sdelphij></H2
6283262685Sdelphij><P
6284262685Sdelphij>Well. If you have seen those forms on web pages which take input from users and
6285262685Sdelphijdo various kinds of things, you might be wondering how would any one create such
6286262685Sdelphijforms in text mode display. It's quite difficult to write those nifty forms in
6287262685Sdelphijplain ncurses. Forms library tries to provide a basic frame work to build and
6288262685Sdelphijmaintain forms with ease. It has lot of features(functions) which manage
6289262685Sdelphijvalidation, dynamic expansion of fields etc.. Let's see it in full flow.</P
6290262685Sdelphij><P
6291262685Sdelphij>A form is a collection of fields; each field can be either a label(static text)
6292262685Sdelphijor a data-entry location. The forms also library provides functions to divide
6293262685Sdelphijforms into multiple pages. </P
6294262685Sdelphij><DIV
6295262685SdelphijCLASS="SECT2"
6296262685Sdelphij><HR><H3
6297262685SdelphijCLASS="SECT2"
6298262685Sdelphij><A
6299262685SdelphijNAME="FORMBASICS"
6300262685Sdelphij>18.1. The Basics</A
6301262685Sdelphij></H3
6302262685Sdelphij><P
6303262685Sdelphij>Forms are created in much the same way as menus. First the fields related to the
6304262685Sdelphijform are created with new_field(). You can set options for the fields, so that
6305262685Sdelphijthey can be displayed with some fancy attributes, validated before the field
6306262685Sdelphijlooses focus etc.. Then the fields are attached to form. After this, the form
6307262685Sdelphijcan be posted to display and is ready to receive inputs. On the similar lines to
6308262685Sdelphijmenu_driver(), the form is manipulated with form_driver(). We can send requests
6309262685Sdelphijto form_driver to move focus to a certain field, move cursor to end of the field
6310262685Sdelphijetc..  After the user enters values in the fields and validation done, form can
6311262685Sdelphijbe unposted and memory allocated can be freed.</P
6312262685Sdelphij><P
6313262685Sdelphij>The general flow of control of a forms program looks like this.
6314262685Sdelphij
6315262685Sdelphij<P
6316262685Sdelphij></P
6317262685Sdelphij><OL
6318262685SdelphijTYPE="1"
6319262685Sdelphij><LI
6320262685Sdelphij><P
6321262685Sdelphij>Initialize curses</P
6322262685Sdelphij></LI
6323262685Sdelphij><LI
6324262685Sdelphij><P
6325262685Sdelphij>Create fields using new_field(). You can specify the height and
6326262685Sdelphijwidth of the field, and its position on the form.</P
6327262685Sdelphij></LI
6328262685Sdelphij><LI
6329262685Sdelphij><P
6330262685Sdelphij>Create the forms with new_form() by specifying the fields to be
6331262685Sdelphijattached with.</P
6332262685Sdelphij></LI
6333262685Sdelphij><LI
6334262685Sdelphij><P
6335262685Sdelphij>Post the form with form_post() and refresh the screen.</P
6336262685Sdelphij></LI
6337262685Sdelphij><LI
6338262685Sdelphij><P
6339262685Sdelphij>Process the user requests with a loop and do necessary updates
6340262685Sdelphijto form with form_driver.</P
6341262685Sdelphij></LI
6342262685Sdelphij><LI
6343262685Sdelphij><P
6344262685Sdelphij>Unpost the menu with form_unpost()</P
6345262685Sdelphij></LI
6346262685Sdelphij><LI
6347262685Sdelphij><P
6348262685Sdelphij>Free the memory allocated to menu by free_form()</P
6349262685Sdelphij></LI
6350262685Sdelphij><LI
6351262685Sdelphij><P
6352262685Sdelphij>Free the memory allocated to the items with free_field()</P
6353262685Sdelphij></LI
6354262685Sdelphij><LI
6355262685Sdelphij><P
6356262685Sdelphij>End curses</P
6357262685Sdelphij></LI
6358262685Sdelphij></OL
6359262685Sdelphij></P
6360262685Sdelphij><P
6361262685Sdelphij>As you can see, working with forms library is much similar to handling menu
6362262685Sdelphijlibrary.  The following examples will explore various aspects of form
6363262685Sdelphijprocessing. Let's start the journey with a simple example.  first.</P
6364262685Sdelphij></DIV
6365262685Sdelphij><DIV
6366262685SdelphijCLASS="SECT2"
6367262685Sdelphij><HR><H3
6368262685SdelphijCLASS="SECT2"
6369262685Sdelphij><A
6370262685SdelphijNAME="COMPILEFORMS"
6371262685Sdelphij>18.2. Compiling With the Forms Library</A
6372262685Sdelphij></H3
6373262685Sdelphij><P
6374262685Sdelphij>To use forms library functions, you have to include form.h and to link the
6375262685Sdelphijprogram with forms library the flag -lform should be added along with -lncurses
6376262685Sdelphijin that order.</P
6377262685Sdelphij><PRE
6378262685SdelphijCLASS="PROGRAMLISTING"
6379262685Sdelphij>    #include &lt;form.h&gt;
6380166124Srafan    .
6381166124Srafan    .
6382166124Srafan    .
6383166124Srafan
6384262685Sdelphij    compile and link: gcc &lt;program file&gt; -lform -lncurses</PRE
6385262685Sdelphij><DIV
6386262685SdelphijCLASS="EXAMPLE"
6387262685Sdelphij><A
6388262685SdelphijNAME="FFOSI"
6389262685Sdelphij></A
6390262685Sdelphij><P
6391262685Sdelphij><B
6392262685Sdelphij>Example 25.  Forms Basics </B
6393262685Sdelphij></P
6394262685Sdelphij><PRE
6395262685SdelphijCLASS="PROGRAMLISTING"
6396262685Sdelphij><SPAN
6397262685SdelphijCLASS="INLINEMEDIAOBJECT"
6398262685Sdelphij>#include &#60;form.h&#62;
6399166124Srafan
6400166124Srafanint main()
6401262685Sdelphij{	FIELD *field[3];
6402262685Sdelphij	FORM  *my_form;
6403262685Sdelphij	int ch;
6404262685Sdelphij	
6405262685Sdelphij	/* Initialize curses */
6406262685Sdelphij	initscr();
6407262685Sdelphij	cbreak();
6408262685Sdelphij	noecho();
6409262685Sdelphij	keypad(stdscr, TRUE);
6410166124Srafan
6411262685Sdelphij	/* Initialize the fields */
6412262685Sdelphij	field[0] = new_field(1, 10, 4, 18, 0, 0);
6413262685Sdelphij	field[1] = new_field(1, 10, 6, 18, 0, 0);
6414262685Sdelphij	field[2] = NULL;
6415166124Srafan
6416262685Sdelphij	/* Set field options */
6417262685Sdelphij	set_field_back(field[0], A_UNDERLINE); 	/* Print a line for the option 	*/
6418262685Sdelphij	field_opts_off(field[0], O_AUTOSKIP);  	/* Don't go to next field when this */
6419262685Sdelphij						/* Field is filled up 		*/
6420262685Sdelphij	set_field_back(field[1], A_UNDERLINE); 
6421262685Sdelphij	field_opts_off(field[1], O_AUTOSKIP);
6422166124Srafan
6423262685Sdelphij	/* Create the form and post it */
6424262685Sdelphij	my_form = new_form(field);
6425262685Sdelphij	post_form(my_form);
6426262685Sdelphij	refresh();
6427262685Sdelphij	
6428262685Sdelphij	mvprintw(4, 10, "Value 1:");
6429262685Sdelphij	mvprintw(6, 10, "Value 2:");
6430262685Sdelphij	refresh();
6431166124Srafan
6432262685Sdelphij	/* Loop through to get user requests */
6433262685Sdelphij	while((ch = getch()) != KEY_F(1))
6434262685Sdelphij	{	switch(ch)
6435262685Sdelphij		{	case KEY_DOWN:
6436262685Sdelphij				/* Go to next field */
6437262685Sdelphij				form_driver(my_form, REQ_NEXT_FIELD);
6438262685Sdelphij				/* Go to the end of the present buffer */
6439262685Sdelphij				/* Leaves nicely at the last character */
6440262685Sdelphij				form_driver(my_form, REQ_END_LINE);
6441262685Sdelphij				break;
6442262685Sdelphij			case KEY_UP:
6443262685Sdelphij				/* Go to previous field */
6444262685Sdelphij				form_driver(my_form, REQ_PREV_FIELD);
6445262685Sdelphij				form_driver(my_form, REQ_END_LINE);
6446262685Sdelphij				break;
6447262685Sdelphij			default:
6448262685Sdelphij				/* If this is a normal character, it gets */
6449262685Sdelphij				/* Printed				  */	
6450262685Sdelphij				form_driver(my_form, ch);
6451262685Sdelphij				break;
6452262685Sdelphij		}
6453262685Sdelphij	}
6454166124Srafan
6455262685Sdelphij	/* Un post form and free the memory */
6456262685Sdelphij	unpost_form(my_form);
6457262685Sdelphij	free_form(my_form);
6458262685Sdelphij	free_field(field[0]);
6459262685Sdelphij	free_field(field[1]); 
6460166124Srafan
6461262685Sdelphij	endwin();
6462262685Sdelphij	return 0;
6463262685Sdelphij}</SPAN
6464262685Sdelphij></PRE
6465262685Sdelphij></DIV
6466262685Sdelphij><P
6467262685Sdelphij>Above example is pretty straight forward. It creates two fields with
6468262685Sdelphij<TT
6469262685SdelphijCLASS="LITERAL"
6470262685Sdelphij>new_field()</TT
6471262685Sdelphij>.  new_field() takes height, width,
6472262685Sdelphijstarty, startx, number of offscreen rows and number of additional working
6473262685Sdelphijbuffers. The fifth argument number of offscreen rows specifies how much of the
6474262685Sdelphijfield to be shown. If it is zero, the entire field is always displayed otherwise
6475262685Sdelphijthe form will be scrollable when the user accesses not displayed parts of the
6476262685Sdelphijfield.  The forms library allocates one buffer per field to store the data user
6477262685Sdelphijenters. Using the last parameter to new_field() we can specify it to allocate
6478262685Sdelphijsome additional buffers.  These can be used for any purpose you like.</P
6479262685Sdelphij><P
6480262685Sdelphij>After creating the fields, back ground attribute of both of them is set to an
6481262685Sdelphijunderscore with set_field_back(). The AUTOSKIP option is turned off using
6482262685Sdelphijfield_opts_off().  If this option is turned on, focus will move to the next
6483262685Sdelphijfield in the form once the active field is filled up completely.</P
6484262685Sdelphij><P
6485262685Sdelphij>After attaching the fields to the form, it is posted. Here on, user inputs are
6486262685Sdelphijprocessed in the while loop, by making corresponding requests to form_driver.
6487262685SdelphijThe details of all the requests to the form_driver() are explained later.</P
6488262685Sdelphij></DIV
6489262685Sdelphij><DIV
6490262685SdelphijCLASS="SECT2"
6491262685Sdelphij><HR><H3
6492262685SdelphijCLASS="SECT2"
6493262685Sdelphij><A
6494262685SdelphijNAME="PLAYFIELDS"
6495262685Sdelphij>18.3. Playing with Fields</A
6496262685Sdelphij></H3
6497262685Sdelphij><P
6498262685Sdelphij>Each form field is associated with a lot of attributes. They can be manipulated
6499262685Sdelphijto get the required effect and to have fun !!!. So why wait? </P
6500262685Sdelphij><DIV
6501262685SdelphijCLASS="SECT3"
6502262685Sdelphij><HR><H4
6503262685SdelphijCLASS="SECT3"
6504262685Sdelphij><A
6505262685SdelphijNAME="FETCHINFO"
6506262685Sdelphij>18.3.1. Fetching Size and Location of Field</A
6507262685Sdelphij></H4
6508262685Sdelphij><P
6509262685Sdelphij>The parameters we have given at the time of creation of a field can be retrieved
6510262685Sdelphijwith field_info(). It returns height, width, starty, startx, number of offscreen
6511262685Sdelphijrows, and number of additional buffers into the parameters given to it. It is a
6512262685Sdelphijsort of inverse of new_field().</P
6513262685Sdelphij><PRE
6514262685SdelphijCLASS="PROGRAMLISTING"
6515262685Sdelphij>int field_info(     FIELD *field,              /* field from which to fetch */
6516166124Srafan                    int *height, *int width,   /* field size */ 
6517166124Srafan                    int *top, int *left,       /* upper left corner */
6518166124Srafan                    int *offscreen,            /* number of offscreen rows */
6519262685Sdelphij                    int *nbuf);                /* number of working buffers */</PRE
6520262685Sdelphij></DIV
6521262685Sdelphij><DIV
6522262685SdelphijCLASS="SECT3"
6523262685Sdelphij><HR><H4
6524262685SdelphijCLASS="SECT3"
6525262685Sdelphij><A
6526262685SdelphijNAME="MOVEFIELD"
6527262685Sdelphij>18.3.2. Moving the field</A
6528262685Sdelphij></H4
6529262685Sdelphij><P
6530262685Sdelphij>The location of the field can be moved to a different position with
6531262685Sdelphijmove_field().</P
6532262685Sdelphij><PRE
6533262685SdelphijCLASS="PROGRAMLISTING"
6534262685Sdelphij>int move_field(    FIELD *field,              /* field to alter */
6535262685Sdelphij                   int top, int left);        /* new upper-left corner */</PRE
6536262685Sdelphij><P
6537262685Sdelphij>As usual, the changed position can be queried with field_infor().</P
6538262685Sdelphij></DIV
6539262685Sdelphij><DIV
6540262685SdelphijCLASS="SECT3"
6541262685Sdelphij><HR><H4
6542262685SdelphijCLASS="SECT3"
6543262685Sdelphij><A
6544262685SdelphijNAME="JUSTIFYFIELD"
6545262685Sdelphij>18.3.3. Field Justification</A
6546262685Sdelphij></H4
6547262685Sdelphij><P
6548262685Sdelphij>The justification to be done for the field can be fixed using the function
6549262685Sdelphijset_field_just().</P
6550262685Sdelphij><PRE
6551262685SdelphijCLASS="PROGRAMLISTING"
6552262685Sdelphij>    int set_field_just(FIELD *field,          /* field to alter */
6553166124Srafan               int justmode);         /* mode to set */
6554262685Sdelphij    int field_just(FIELD *field);          /* fetch justify mode of field */</PRE
6555262685Sdelphij><P
6556262685Sdelphij>The justification mode valued accepted and returned by these functions are 
6557262685SdelphijNO_JUSTIFICATION, JUSTIFY_RIGHT, JUSTIFY_LEFT, or JUSTIFY_CENTER.</P
6558262685Sdelphij></DIV
6559262685Sdelphij><DIV
6560262685SdelphijCLASS="SECT3"
6561262685Sdelphij><HR><H4
6562262685SdelphijCLASS="SECT3"
6563262685Sdelphij><A
6564262685SdelphijNAME="FIELDDISPATTRIB"
6565262685Sdelphij>18.3.4. Field Display Attributes</A
6566262685Sdelphij></H4
6567262685Sdelphij><P
6568262685Sdelphij>As you have seen, in the above example, display attribute for the fields can be
6569262685Sdelphijset with set_field_fore() and setfield_back(). These functions set foreground
6570262685Sdelphijand background attribute of the fields. You can also specify a pad character
6571262685Sdelphijwhich will be filled in the unfilled portion of the field. The pad character is
6572262685Sdelphijset with a call to set_field_pad(). Default pad value is a space. The functions
6573262685Sdelphijfield_fore(), field_back, field_pad() can be used to query the present
6574262685Sdelphijforeground, background attributes and pad character for the field. The following
6575262685Sdelphijlist gives the usage of functions.</P
6576262685Sdelphij><PRE
6577262685SdelphijCLASS="PROGRAMLISTING"
6578262685Sdelphij>&#13;int set_field_fore(FIELD *field,        /* field to alter */
6579166124Srafan                   chtype attr);        /* attribute to set */ 
6580166124Srafan
6581166124Srafanchtype field_fore(FIELD *field);        /* field to query */
6582166124Srafan                                        /* returns foreground attribute */
6583166124Srafan
6584166124Srafanint set_field_back(FIELD *field,        /* field to alter */
6585166124Srafan                   chtype attr);        /* attribute to set */ 
6586166124Srafan
6587166124Srafanchtype field_back(FIELD *field);        /* field to query */
6588166124Srafan                                        /* returns background attribute */
6589166124Srafan
6590166124Srafanint set_field_pad(FIELD *field,         /* field to alter */
6591166124Srafan                  int pad);             /* pad character to set */ 
6592166124Srafan
6593166124Srafanchtype field_pad(FIELD *field);         /* field to query */  
6594262685Sdelphij                                        /* returns present pad character */&#13;</PRE
6595262685Sdelphij><P
6596262685Sdelphij>Though above functions seem quite simple, using colors with set_field_fore() may
6597262685Sdelphijbe frustrating in the beginning. Let me first explain about foreground and
6598262685Sdelphijbackground attributes of a field. The foreground attribute is associated with
6599262685Sdelphijthe character. That means a character in the field is printed with the attribute
6600262685Sdelphijyou have set with set_field_fore(). Background attribute is the attribute used
6601262685Sdelphijto fill background of field, whether any character is there or not.  So what
6602262685Sdelphijabout colors? Since colors are always defined in pairs, what is the right way to
6603262685Sdelphijdisplay colored fields? Here's an example clarifying color attributes.</P
6604262685Sdelphij><DIV
6605262685SdelphijCLASS="EXAMPLE"
6606262685Sdelphij><A
6607262685SdelphijNAME="FFOAT"
6608262685Sdelphij></A
6609262685Sdelphij><P
6610262685Sdelphij><B
6611262685Sdelphij>Example 26.  Form Attributes example </B
6612262685Sdelphij></P
6613262685Sdelphij><PRE
6614262685SdelphijCLASS="PROGRAMLISTING"
6615262685Sdelphij><SPAN
6616262685SdelphijCLASS="INLINEMEDIAOBJECT"
6617262685Sdelphij>#include &#60;form.h&#62;
6618166124Srafan
6619166124Srafanint main()
6620262685Sdelphij{	FIELD *field[3];
6621262685Sdelphij	FORM  *my_form;
6622262685Sdelphij	int ch;
6623262685Sdelphij	
6624262685Sdelphij	/* Initialize curses */
6625262685Sdelphij	initscr();
6626262685Sdelphij	start_color();
6627262685Sdelphij	cbreak();
6628262685Sdelphij	noecho();
6629262685Sdelphij	keypad(stdscr, TRUE);
6630166124Srafan
6631262685Sdelphij	/* Initialize few color pairs */
6632262685Sdelphij	init_pair(1, COLOR_WHITE, COLOR_BLUE);
6633262685Sdelphij	init_pair(2, COLOR_WHITE, COLOR_BLUE);
6634166124Srafan
6635262685Sdelphij	/* Initialize the fields */
6636262685Sdelphij	field[0] = new_field(1, 10, 4, 18, 0, 0);
6637262685Sdelphij	field[1] = new_field(1, 10, 6, 18, 0, 0);
6638262685Sdelphij	field[2] = NULL;
6639166124Srafan
6640262685Sdelphij	/* Set field options */
6641262685Sdelphij	set_field_fore(field[0], COLOR_PAIR(1));/* Put the field with blue background */
6642262685Sdelphij	set_field_back(field[0], COLOR_PAIR(2));/* and white foreground (characters */
6643262685Sdelphij						/* are printed in white 	*/
6644262685Sdelphij	field_opts_off(field[0], O_AUTOSKIP);  	/* Don't go to next field when this */
6645262685Sdelphij						/* Field is filled up 		*/
6646262685Sdelphij	set_field_back(field[1], A_UNDERLINE); 
6647262685Sdelphij	field_opts_off(field[1], O_AUTOSKIP);
6648166124Srafan
6649262685Sdelphij	/* Create the form and post it */
6650262685Sdelphij	my_form = new_form(field);
6651262685Sdelphij	post_form(my_form);
6652262685Sdelphij	refresh();
6653262685Sdelphij	
6654262685Sdelphij	set_current_field(my_form, field[0]); /* Set focus to the colored field */
6655262685Sdelphij	mvprintw(4, 10, "Value 1:");
6656262685Sdelphij	mvprintw(6, 10, "Value 2:");
6657262685Sdelphij	mvprintw(LINES - 2, 0, "Use UP, DOWN arrow keys to switch between fields");
6658262685Sdelphij	refresh();
6659166124Srafan
6660262685Sdelphij	/* Loop through to get user requests */
6661262685Sdelphij	while((ch = getch()) != KEY_F(1))
6662262685Sdelphij	{	switch(ch)
6663262685Sdelphij		{	case KEY_DOWN:
6664262685Sdelphij				/* Go to next field */
6665262685Sdelphij				form_driver(my_form, REQ_NEXT_FIELD);
6666262685Sdelphij				/* Go to the end of the present buffer */
6667262685Sdelphij				/* Leaves nicely at the last character */
6668262685Sdelphij				form_driver(my_form, REQ_END_LINE);
6669262685Sdelphij				break;
6670262685Sdelphij			case KEY_UP:
6671262685Sdelphij				/* Go to previous field */
6672262685Sdelphij				form_driver(my_form, REQ_PREV_FIELD);
6673262685Sdelphij				form_driver(my_form, REQ_END_LINE);
6674262685Sdelphij				break;
6675262685Sdelphij			default:
6676262685Sdelphij				/* If this is a normal character, it gets */
6677262685Sdelphij				/* Printed				  */	
6678262685Sdelphij				form_driver(my_form, ch);
6679262685Sdelphij				break;
6680262685Sdelphij		}
6681262685Sdelphij	}
6682166124Srafan
6683262685Sdelphij	/* Un post form and free the memory */
6684262685Sdelphij	unpost_form(my_form);
6685262685Sdelphij	free_form(my_form);
6686262685Sdelphij	free_field(field[0]);
6687262685Sdelphij	free_field(field[1]); 
6688166124Srafan
6689262685Sdelphij	endwin();
6690262685Sdelphij	return 0;
6691262685Sdelphij}</SPAN
6692262685Sdelphij></PRE
6693262685Sdelphij></DIV
6694262685Sdelphij><P
6695262685Sdelphij>Play with the color pairs and try to understand the foreground and background
6696262685Sdelphijattributes. In my programs using color attributes, I usually set only the
6697262685Sdelphijbackground with set_field_back(). Curses simply doesn't allow defining
6698262685Sdelphijindividual color attributes. </P
6699262685Sdelphij></DIV
6700262685Sdelphij><DIV
6701262685SdelphijCLASS="SECT3"
6702262685Sdelphij><HR><H4
6703262685SdelphijCLASS="SECT3"
6704262685Sdelphij><A
6705262685SdelphijNAME="FIELDOPTIONBITS"
6706262685Sdelphij>18.3.5. Field Option Bits</A
6707262685Sdelphij></H4
6708262685Sdelphij><P
6709262685Sdelphij>There is also a large collection of field option bits you can set to control
6710262685Sdelphijvarious aspects of forms processing. You can manipulate them with these
6711262685Sdelphijfunctions:</P
6712262685Sdelphij><PRE
6713262685SdelphijCLASS="PROGRAMLISTING"
6714262685Sdelphij>int set_field_opts(FIELD *field,          /* field to alter */
6715166124Srafan                   int attr);             /* attribute to set */ 
6716166124Srafan
6717166124Srafanint field_opts_on(FIELD *field,           /* field to alter */
6718166124Srafan                  int attr);              /* attributes to turn on */ 
6719166124Srafan
6720166124Srafanint field_opts_off(FIELD *field,          /* field to alter */
6721166124Srafan                  int attr);              /* attributes to turn off */ 
6722166124Srafan
6723262685Sdelphijint field_opts(FIELD *field);             /* field to query */ </PRE
6724262685Sdelphij><P
6725262685Sdelphij>The function set_field_opts() can be used to directly set attributes of a field
6726262685Sdelphijor you can choose to switch a few attributes on and off with field_opts_on() and
6727262685Sdelphijfield_opts_off() selectively. Anytime you can query the attributes of a field
6728262685Sdelphijwith field_opts(). The following is the list of available options. By default,
6729262685Sdelphijall options are on.</P
6730262685Sdelphij><P
6731262685Sdelphij></P
6732262685Sdelphij><DIV
6733262685SdelphijCLASS="VARIABLELIST"
6734262685Sdelphij><DL
6735262685Sdelphij><DT
6736262685Sdelphij>O_VISIBLE</DT
6737262685Sdelphij><DD
6738262685Sdelphij><P
6739262685Sdelphij>Controls whether the field is visible on the screen.  Can be used
6740262685Sdelphijduring form processing to hide or pop up fields depending on the value
6741262685Sdelphijof parent fields.</P
6742262685Sdelphij></DD
6743262685Sdelphij><DT
6744262685Sdelphij>O_ACTIVE</DT
6745262685Sdelphij><DD
6746262685Sdelphij><P
6747262685Sdelphij>Controls whether the field is active during forms processing (i.e.
6748262685Sdelphijvisited by form navigation keys).  Can be used to make labels or derived
6749262685Sdelphijfields with buffer values alterable by the forms application, not the user.</P
6750262685Sdelphij></DD
6751262685Sdelphij><DT
6752262685Sdelphij>O_PUBLIC</DT
6753262685Sdelphij><DD
6754262685Sdelphij><P
6755262685Sdelphij>Controls whether data is displayed during field entry.  If this option is
6756262685Sdelphijturned off on a field, the library will accept and edit data in that field,
6757262685Sdelphijbut it will not be displayed and the visible field cursor will not move.
6758262685SdelphijYou can turn off the O_PUBLIC bit to define password fields.</P
6759262685Sdelphij></DD
6760262685Sdelphij><DT
6761262685Sdelphij>O_EDIT</DT
6762262685Sdelphij><DD
6763262685Sdelphij><P
6764262685Sdelphij>Controls whether the field's data can be modified.  When this option is
6765262685Sdelphijoff, all editing requests except <TT
6766262685SdelphijCLASS="LITERAL"
6767262685Sdelphij>REQ_PREV_CHOICE</TT
6768262685Sdelphij> and <TT
6769262685SdelphijCLASS="LITERAL"
6770262685Sdelphij>REQ_NEXT_CHOICE</TT
6771262685Sdelphij>will 
6772262685Sdelphijfail.  Such read-only fields may be useful for help messages.</P
6773262685Sdelphij></DD
6774262685Sdelphij><DT
6775262685Sdelphij>O_WRAP</DT
6776262685Sdelphij><DD
6777262685Sdelphij><P
6778262685Sdelphij>Controls word-wrapping in multi-line fields.  Normally, when any
6779262685Sdelphijcharacter of a (blank-separated) word reaches the end of the current line, the
6780262685Sdelphijentire word is wrapped to the next line (assuming there is one).  When this
6781262685Sdelphijoption is off, the word will be split across the line break.</P
6782262685Sdelphij></DD
6783262685Sdelphij><DT
6784262685Sdelphij>O_BLANK</DT
6785262685Sdelphij><DD
6786262685Sdelphij><P
6787262685Sdelphij>Controls field blanking.  When this option is on, entering a character at
6788262685Sdelphijthe first field position erases the entire field (except for the just-entered
6789262685Sdelphijcharacter).</P
6790262685Sdelphij></DD
6791262685Sdelphij><DT
6792262685Sdelphij>O_AUTOSKIP</DT
6793262685Sdelphij><DD
6794262685Sdelphij><P
6795262685Sdelphij>Controls automatic skip to next field when this one fills.  Normally,
6796262685Sdelphijwhen the forms user tries to type more data into a field than will fit,
6797262685Sdelphijthe editing location jumps to next field.  When this option is off, the
6798262685Sdelphijuser's cursor will hang at the end of the field.  This option is ignored
6799262685Sdelphijin dynamic fields that have not reached their size limit.</P
6800262685Sdelphij></DD
6801262685Sdelphij><DT
6802262685Sdelphij>O_NULLOK</DT
6803262685Sdelphij><DD
6804262685Sdelphij><P
6805262685Sdelphij>Controls whether validation is applied to
6806262685Sdelphijblank fields.  Normally, it is not; the user can leave a field blank
6807262685Sdelphijwithout invoking the usual validation check on exit.  If this option is
6808262685Sdelphijoff on a field, exit from it will invoke a validation check.</P
6809262685Sdelphij></DD
6810262685Sdelphij><DT
6811262685Sdelphij>O_PASSOK</DT
6812262685Sdelphij><DD
6813262685Sdelphij><P
6814262685Sdelphij>Controls whether validation occurs on every exit, or only after
6815262685Sdelphijthe field is modified.  Normally the latter is true.  Setting O_PASSOK
6816262685Sdelphijmay be useful if your field's validation function may change during
6817262685Sdelphijforms processing.</P
6818262685Sdelphij></DD
6819262685Sdelphij><DT
6820262685Sdelphij>O_STATIC</DT
6821262685Sdelphij><DD
6822262685Sdelphij><P
6823262685Sdelphij>Controls whether the field is fixed to its initial dimensions.  If you
6824262685Sdelphijturn this off, the field becomes dynamic and will
6825262685Sdelphijstretch to fit entered data.</P
6826262685Sdelphij></DD
6827262685Sdelphij></DL
6828262685Sdelphij></DIV
6829262685Sdelphij><P
6830262685Sdelphij>A field's options cannot be changed while the field is currently selected.
6831262685SdelphijHowever, options may be changed on posted fields that are not current. </P
6832262685Sdelphij><P
6833262685Sdelphij>The option values are bit-masks and can be composed with logical-or in
6834262685Sdelphijthe obvious way. You have seen the usage of switching off O_AUTOSKIP option.
6835262685SdelphijThe following example clarifies usage of some more options. Other options
6836262685Sdelphijare explained where appropriate.</P
6837262685Sdelphij><DIV
6838262685SdelphijCLASS="EXAMPLE"
6839262685Sdelphij><A
6840262685SdelphijNAME="FFOOP"
6841262685Sdelphij></A
6842262685Sdelphij><P
6843262685Sdelphij><B
6844262685Sdelphij>Example 27.  Field Options Usage example </B
6845262685Sdelphij></P
6846262685Sdelphij><PRE
6847262685SdelphijCLASS="PROGRAMLISTING"
6848262685Sdelphij><SPAN
6849262685SdelphijCLASS="INLINEMEDIAOBJECT"
6850262685Sdelphij>#include &#60;form.h&#62;
6851166124Srafan
6852166124Srafan#define STARTX 15
6853166124Srafan#define STARTY 4
6854166124Srafan#define WIDTH 25
6855166124Srafan
6856166124Srafan#define N_FIELDS 3
6857166124Srafan
6858166124Srafanint main()
6859262685Sdelphij{	FIELD *field[N_FIELDS];
6860262685Sdelphij	FORM  *my_form;
6861262685Sdelphij	int ch, i;
6862262685Sdelphij	
6863262685Sdelphij	/* Initialize curses */
6864262685Sdelphij	initscr();
6865262685Sdelphij	cbreak();
6866262685Sdelphij	noecho();
6867262685Sdelphij	keypad(stdscr, TRUE);
6868166124Srafan
6869262685Sdelphij	/* Initialize the fields */
6870262685Sdelphij	for(i = 0; i &#60; N_FIELDS - 1; ++i)
6871262685Sdelphij		field[i] = new_field(1, WIDTH, STARTY + i * 2, STARTX, 0, 0);
6872262685Sdelphij	field[N_FIELDS - 1] = NULL;
6873166124Srafan
6874262685Sdelphij	/* Set field options */
6875262685Sdelphij	set_field_back(field[1], A_UNDERLINE); 	/* Print a line for the option 	*/
6876262685Sdelphij	
6877262685Sdelphij	field_opts_off(field[0], O_ACTIVE); /* This field is a static label */
6878262685Sdelphij	field_opts_off(field[1], O_PUBLIC); /* This filed is like a password field*/
6879262685Sdelphij	field_opts_off(field[1], O_AUTOSKIP); /* To avoid entering the same field */
6880262685Sdelphij					      /* after last character is entered */
6881262685Sdelphij	
6882262685Sdelphij	/* Create the form and post it */
6883262685Sdelphij	my_form = new_form(field);
6884262685Sdelphij	post_form(my_form);
6885262685Sdelphij	refresh();
6886262685Sdelphij	
6887262685Sdelphij	set_field_just(field[0], JUSTIFY_CENTER); /* Center Justification */
6888262685Sdelphij	set_field_buffer(field[0], 0, "This is a static Field"); 
6889262685Sdelphij						  /* Initialize the field  */
6890262685Sdelphij	mvprintw(STARTY, STARTX - 10, "Field 1:");
6891262685Sdelphij	mvprintw(STARTY + 2, STARTX - 10, "Field 2:");
6892262685Sdelphij	refresh();
6893166124Srafan
6894262685Sdelphij	/* Loop through to get user requests */
6895262685Sdelphij	while((ch = getch()) != KEY_F(1))
6896262685Sdelphij	{	switch(ch)
6897262685Sdelphij		{	case KEY_DOWN:
6898262685Sdelphij				/* Go to next field */
6899262685Sdelphij				form_driver(my_form, REQ_NEXT_FIELD);
6900262685Sdelphij				/* Go to the end of the present buffer */
6901262685Sdelphij				/* Leaves nicely at the last character */
6902262685Sdelphij				form_driver(my_form, REQ_END_LINE);
6903262685Sdelphij				break;
6904262685Sdelphij			case KEY_UP:
6905262685Sdelphij				/* Go to previous field */
6906262685Sdelphij				form_driver(my_form, REQ_PREV_FIELD);
6907262685Sdelphij				form_driver(my_form, REQ_END_LINE);
6908262685Sdelphij				break;
6909262685Sdelphij			default:
6910262685Sdelphij				/* If this is a normal character, it gets */
6911262685Sdelphij				/* Printed				  */	
6912262685Sdelphij				form_driver(my_form, ch);
6913262685Sdelphij				break;
6914262685Sdelphij		}
6915262685Sdelphij	}
6916166124Srafan
6917262685Sdelphij	/* Un post form and free the memory */
6918262685Sdelphij	unpost_form(my_form);
6919262685Sdelphij	free_form(my_form);
6920262685Sdelphij	free_field(field[0]);
6921262685Sdelphij	free_field(field[1]); 
6922166124Srafan
6923262685Sdelphij	endwin();
6924262685Sdelphij	return 0;
6925262685Sdelphij}</SPAN
6926262685Sdelphij></PRE
6927262685Sdelphij></DIV
6928262685Sdelphij><P
6929262685Sdelphij>This example, though useless, shows the usage of options. If used properly, they
6930262685Sdelphijcan present information very effectively in a form. The second field being not
6931262685SdelphijO_PUBLIC, does not show the characters you are typing.</P
6932262685Sdelphij></DIV
6933262685Sdelphij><DIV
6934262685SdelphijCLASS="SECT3"
6935262685Sdelphij><HR><H4
6936262685SdelphijCLASS="SECT3"
6937262685Sdelphij><A
6938262685SdelphijNAME="FIELDSTATUS"
6939262685Sdelphij>18.3.6. Field Status</A
6940262685Sdelphij></H4
6941262685Sdelphij><P
6942262685Sdelphij>The field status specifies whether the field has got edited or not. It is
6943262685Sdelphijinitially set to FALSE and when user enters something and the data buffer gets
6944262685Sdelphijmodified it becomes TRUE. So a field's status can be queried to find out whether
6945262685Sdelphijit has been modified or not. The following functions can assist in those
6946262685Sdelphijoperations.</P
6947262685Sdelphij><PRE
6948262685SdelphijCLASS="PROGRAMLISTING"
6949262685Sdelphij>int set_field_status(FIELD *field,      /* field to alter */
6950166124Srafan                   int status);         /* status to set */
6951166124Srafan
6952262685Sdelphijint field_status(FIELD *field);         /* fetch status of field */</PRE
6953262685Sdelphij><P
6954262685Sdelphij>It's better to check the field's status only after after leaving the field, as
6955262685Sdelphijdata buffer might not have been updated yet as the validation is still due. To
6956262685Sdelphijguarantee that right status is returned, call field_status() either (1) in the
6957262685Sdelphijfield's exit validation check routine, (2) from the field's or form's
6958262685Sdelphijinitialization or termination hooks, or (3) just after a REQ_VALIDATION request
6959262685Sdelphijhas been processed by the forms driver</P
6960262685Sdelphij></DIV
6961262685Sdelphij><DIV
6962262685SdelphijCLASS="SECT3"
6963262685Sdelphij><HR><H4
6964262685SdelphijCLASS="SECT3"
6965262685Sdelphij><A
6966262685SdelphijNAME="FIELDUSERPTR"
6967262685Sdelphij>18.3.7. Field User Pointer</A
6968262685Sdelphij></H4
6969262685Sdelphij><P
6970262685Sdelphij>Every field structure contains one pointer that can be used by the user for
6971262685Sdelphijvarious purposes. It is not touched by forms library and can be used for any
6972262685Sdelphijpurpose by the user. The following functions set and fetch user pointer.</P
6973262685Sdelphij><PRE
6974262685SdelphijCLASS="PROGRAMLISTING"
6975262685Sdelphij>int set_field_userptr(FIELD *field,   
6976166124Srafan           char *userptr);      /* the user pointer you wish to associate */
6977166124Srafan                                /* with the field    */
6978166124Srafan
6979262685Sdelphijchar *field_userptr(FIELD *field);      /* fetch user pointer of the field */</PRE
6980262685Sdelphij></DIV
6981262685Sdelphij><DIV
6982262685SdelphijCLASS="SECT3"
6983262685Sdelphij><HR><H4
6984262685SdelphijCLASS="SECT3"
6985262685Sdelphij><A
6986262685SdelphijNAME="VARIABLESIZEFIELDS"
6987262685Sdelphij>18.3.8. Variable-Sized Fields</A
6988262685Sdelphij></H4
6989262685Sdelphij><P
6990262685Sdelphij>If you want a dynamically changing field with variable width, this is the
6991262685Sdelphijfeature you want to put to full use. This will allow the user to enter more data
6992262685Sdelphijthan the original size of the field and let the field grow. According to the
6993262685Sdelphijfield orientation it will scroll horizontally or vertically to incorporate the
6994262685Sdelphijnew data.</P
6995262685Sdelphij><P
6996262685Sdelphij>To make a field dynamically growable, the option O_STATIC should be turned off.
6997262685SdelphijThis can be done with a 
6998262685Sdelphij<PRE
6999262685SdelphijCLASS="PROGRAMLISTING"
7000262685Sdelphij>    field_opts_off(field_pointer, O_STATIC);</PRE
7001262685Sdelphij></P
7002262685Sdelphij><P
7003262685Sdelphij>But it's usually not advisable to allow a field to grow infinitely. You can set
7004262685Sdelphija maximum limit to the growth of the field with 
7005262685Sdelphij<PRE
7006262685SdelphijCLASS="PROGRAMLISTING"
7007262685Sdelphij>int set_max_field(FIELD *field,    /* Field on which to operate */
7008262685Sdelphij                  int max_growth); /* maximum growth allowed for the field */</PRE
7009262685Sdelphij></P
7010262685Sdelphij><P
7011262685Sdelphij>The field info for a dynamically growable field can be retrieved by 
7012262685Sdelphij<PRE
7013262685SdelphijCLASS="PROGRAMLISTING"
7014262685Sdelphij>int dynamic_field_info( FIELD *field,     /* Field on which to operate */
7015166124Srafan            int   *prows,     /* number of rows will be filled in this */
7016166124Srafan            int   *pcols,     /* number of columns will be filled in this*/
7017166124Srafan            int   *pmax)      /* maximum allowable growth will be filled */
7018262685Sdelphij                              /* in this */</PRE
7019262685Sdelphij>
7020262685SdelphijThough field_info work as usual, it is advisable to use this function to get the
7021262685Sdelphijproper attributes of a dynamically growable field.</P
7022262685Sdelphij><P
7023262685Sdelphij>Recall the library routine new_field; a new field created with height set to one
7024262685Sdelphijwill be defined to be a one line field. A new field created with height greater
7025262685Sdelphijthan one will be defined to be a multi line field. </P
7026262685Sdelphij><P
7027262685Sdelphij>A one line field with O_STATIC turned off (dynamically growable field)  will
7028262685Sdelphijcontain a single fixed row, but the number of columns can increase if the user
7029262685Sdelphijenters more data than the initial field will hold. The number of columns
7030262685Sdelphijdisplayed will remain fixed and the additional data will scroll horizontally. </P
7031262685Sdelphij><P
7032262685Sdelphij>A multi line field with O_STATIC turned off (dynamically growable field) will
7033262685Sdelphijcontain a fixed number of columns, but the number of rows can increase if the
7034262685Sdelphijuser enters more data than the initial field will hold. The number of rows
7035262685Sdelphijdisplayed will remain fixed and the additional data will scroll vertically.</P
7036262685Sdelphij><P
7037262685Sdelphij>The above two paragraphs pretty much describe a dynamically growable field's 
7038262685Sdelphijbehavior. The way other parts of forms library behaves is described below:</P
7039262685Sdelphij><P
7040262685Sdelphij></P
7041262685Sdelphij><OL
7042262685SdelphijTYPE="1"
7043262685Sdelphij><LI
7044262685Sdelphij><P
7045262685Sdelphij>The field option O_AUTOSKIP will be ignored if the option O_STATIC is off and
7046262685Sdelphijthere is no maximum growth specified for the field. Currently, O_AUTOSKIP
7047262685Sdelphijgenerates an automatic REQ_NEXT_FIELD form driver request when the user types in
7048262685Sdelphijthe last character position of a field. On a growable field with no maximum
7049262685Sdelphijgrowth specified, there is no last character position. If a maximum growth is
7050262685Sdelphijspecified, the O_AUTOSKIP option will work as normal if the field has grown to
7051262685Sdelphijits maximum size. </P
7052262685Sdelphij></LI
7053262685Sdelphij><LI
7054262685Sdelphij><P
7055262685Sdelphij>The field justification will be ignored if the option O_STATIC is off.
7056262685SdelphijCurrently, set_field_just can be used to JUSTIFY_LEFT, JUSTIFY_RIGHT,
7057262685SdelphijJUSTIFY_CENTER the contents of a one line field. A growable one line field will,
7058262685Sdelphijby definition, grow and scroll horizontally and may contain more data than can
7059262685Sdelphijbe justified. The return from field_just will be unchanged. </P
7060262685Sdelphij></LI
7061262685Sdelphij><LI
7062262685Sdelphij><P
7063262685Sdelphij>The overloaded form driver request REQ_NEW_LINE will operate the same way
7064262685Sdelphijregardless of the O_NL_OVERLOAD form option if the field option O_STATIC is off
7065262685Sdelphijand there is no maximum growth specified for the field. Currently, if the form
7066262685Sdelphijoption O_NL_OVERLOAD is on, REQ_NEW_LINE implicitly generates a REQ_NEXT_FIELD
7067262685Sdelphijif called from the last line of a field. If a field can grow without bound,
7068262685Sdelphijthere is no last line, so REQ_NEW_LINE will never implicitly generate a
7069262685SdelphijREQ_NEXT_FIELD. If a maximum growth limit is specified and the O_NL_OVERLOAD
7070262685Sdelphijform option is on, REQ_NEW_LINE will only implicitly generate REQ_NEXT_FIELD if
7071262685Sdelphijthe field has grown to its maximum size and the user is on the last line. </P
7072262685Sdelphij></LI
7073262685Sdelphij><LI
7074262685Sdelphij><P
7075262685Sdelphij>The library call dup_field will work as usual; it will duplicate the field,
7076262685Sdelphijincluding the current buffer size and contents of the field being duplicated.
7077262685SdelphijAny specified maximum growth will also be duplicated. </P
7078262685Sdelphij></LI
7079262685Sdelphij><LI
7080262685Sdelphij><P
7081262685Sdelphij>The library call link_field will work as usual; it will duplicate all field
7082262685Sdelphijattributes and share buffers with the field being linked. If the O_STATIC field
7083262685Sdelphijoption is subsequently changed by a field sharing buffers, how the system reacts
7084262685Sdelphijto an attempt to enter more data into the field than the buffer will currently
7085262685Sdelphijhold will depend on the setting of the option in the current field. </P
7086262685Sdelphij></LI
7087262685Sdelphij><LI
7088262685Sdelphij><P
7089262685Sdelphij>The library call field_info will work as usual; the variable nrow will contain
7090262685Sdelphijthe value of the original call to new_field. The user should use
7091262685Sdelphijdynamic_field_info, described above, to query the current size of the buffer.</P
7092262685Sdelphij></LI
7093262685Sdelphij></OL
7094262685Sdelphij><P
7095262685Sdelphij>Some of the above points make sense only after explaining form driver. We will
7096262685Sdelphijbe looking into that in next few sections.</P
7097262685Sdelphij></DIV
7098262685Sdelphij></DIV
7099262685Sdelphij><DIV
7100262685SdelphijCLASS="SECT2"
7101262685Sdelphij><HR><H3
7102262685SdelphijCLASS="SECT2"
7103262685Sdelphij><A
7104262685SdelphijNAME="FORMWINDOWS"
7105262685Sdelphij>18.4. Form Windows</A
7106262685Sdelphij></H3
7107262685Sdelphij><P
7108262685Sdelphij>The form windows concept is pretty much similar to menu windows. Every form is
7109262685Sdelphijassociated with a main window and a sub window. The form main window displays
7110262685Sdelphijany title or border associated or whatever the user wishes. Then the sub window
7111262685Sdelphijcontains all the fields and displays them according to their position. This
7112262685Sdelphijgives the flexibility of manipulating fancy form displaying very easily. </P
7113262685Sdelphij><P
7114262685Sdelphij>Since this is pretty much similar to menu windows, I am providing an example
7115262685Sdelphijwith out much explanation. The functions are similar and they work the same way.</P
7116262685Sdelphij><DIV
7117262685SdelphijCLASS="EXAMPLE"
7118262685Sdelphij><A
7119262685SdelphijNAME="FFOWI"
7120262685Sdelphij></A
7121262685Sdelphij><P
7122262685Sdelphij><B
7123262685Sdelphij>Example 28.  Form Windows Example </B
7124262685Sdelphij></P
7125262685Sdelphij><PRE
7126262685SdelphijCLASS="PROGRAMLISTING"
7127262685Sdelphij><SPAN
7128262685SdelphijCLASS="INLINEMEDIAOBJECT"
7129262685Sdelphij>#include &#60;form.h&#62;
7130166124Srafan
7131166124Srafanvoid print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color);
7132166124Srafan
7133166124Srafanint main()
7134166124Srafan{
7135262685Sdelphij	FIELD *field[3];
7136262685Sdelphij	FORM  *my_form;
7137262685Sdelphij	WINDOW *my_form_win;
7138262685Sdelphij	int ch, rows, cols;
7139262685Sdelphij	
7140262685Sdelphij	/* Initialize curses */
7141262685Sdelphij	initscr();
7142262685Sdelphij	start_color();
7143262685Sdelphij	cbreak();
7144262685Sdelphij	noecho();
7145262685Sdelphij	keypad(stdscr, TRUE);
7146166124Srafan
7147262685Sdelphij	/* Initialize few color pairs */
7148262685Sdelphij   	init_pair(1, COLOR_RED, COLOR_BLACK);
7149166124Srafan
7150262685Sdelphij	/* Initialize the fields */
7151262685Sdelphij	field[0] = new_field(1, 10, 6, 1, 0, 0);
7152262685Sdelphij	field[1] = new_field(1, 10, 8, 1, 0, 0);
7153262685Sdelphij	field[2] = NULL;
7154166124Srafan
7155262685Sdelphij	/* Set field options */
7156262685Sdelphij	set_field_back(field[0], A_UNDERLINE);
7157262685Sdelphij	field_opts_off(field[0], O_AUTOSKIP); /* Don't go to next field when this */
7158262685Sdelphij					      /* Field is filled up 		*/
7159262685Sdelphij	set_field_back(field[1], A_UNDERLINE); 
7160262685Sdelphij	field_opts_off(field[1], O_AUTOSKIP);
7161262685Sdelphij	
7162262685Sdelphij	/* Create the form and post it */
7163262685Sdelphij	my_form = new_form(field);
7164262685Sdelphij	
7165262685Sdelphij	/* Calculate the area required for the form */
7166262685Sdelphij	scale_form(my_form, &#38;rows, &#38;cols);
7167166124Srafan
7168262685Sdelphij	/* Create the window to be associated with the form */
7169166124Srafan        my_form_win = newwin(rows + 4, cols + 4, 4, 4);
7170166124Srafan        keypad(my_form_win, TRUE);
7171166124Srafan
7172262685Sdelphij	/* Set main window and sub window */
7173166124Srafan        set_form_win(my_form, my_form_win);
7174166124Srafan        set_form_sub(my_form, derwin(my_form_win, rows, cols, 2, 2));
7175166124Srafan
7176262685Sdelphij	/* Print a border around the main window and print a title */
7177166124Srafan        box(my_form_win, 0, 0);
7178262685Sdelphij	print_in_middle(my_form_win, 1, 0, cols + 4, "My Form", COLOR_PAIR(1));
7179262685Sdelphij	
7180262685Sdelphij	post_form(my_form);
7181262685Sdelphij	wrefresh(my_form_win);
7182166124Srafan
7183262685Sdelphij	mvprintw(LINES - 2, 0, "Use UP, DOWN arrow keys to switch between fields");
7184262685Sdelphij	refresh();
7185166124Srafan
7186262685Sdelphij	/* Loop through to get user requests */
7187262685Sdelphij	while((ch = wgetch(my_form_win)) != KEY_F(1))
7188262685Sdelphij	{	switch(ch)
7189262685Sdelphij		{	case KEY_DOWN:
7190262685Sdelphij				/* Go to next field */
7191262685Sdelphij				form_driver(my_form, REQ_NEXT_FIELD);
7192262685Sdelphij				/* Go to the end of the present buffer */
7193262685Sdelphij				/* Leaves nicely at the last character */
7194262685Sdelphij				form_driver(my_form, REQ_END_LINE);
7195262685Sdelphij				break;
7196262685Sdelphij			case KEY_UP:
7197262685Sdelphij				/* Go to previous field */
7198262685Sdelphij				form_driver(my_form, REQ_PREV_FIELD);
7199262685Sdelphij				form_driver(my_form, REQ_END_LINE);
7200262685Sdelphij				break;
7201262685Sdelphij			default:
7202262685Sdelphij				/* If this is a normal character, it gets */
7203262685Sdelphij				/* Printed				  */	
7204262685Sdelphij				form_driver(my_form, ch);
7205262685Sdelphij				break;
7206262685Sdelphij		}
7207262685Sdelphij	}
7208166124Srafan
7209262685Sdelphij	/* Un post form and free the memory */
7210262685Sdelphij	unpost_form(my_form);
7211262685Sdelphij	free_form(my_form);
7212262685Sdelphij	free_field(field[0]);
7213262685Sdelphij	free_field(field[1]); 
7214166124Srafan
7215262685Sdelphij	endwin();
7216262685Sdelphij	return 0;
7217166124Srafan}
7218166124Srafan
7219166124Srafanvoid print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color)
7220262685Sdelphij{	int length, x, y;
7221262685Sdelphij	float temp;
7222166124Srafan
7223262685Sdelphij	if(win == NULL)
7224262685Sdelphij		win = stdscr;
7225262685Sdelphij	getyx(win, y, x);
7226262685Sdelphij	if(startx != 0)
7227262685Sdelphij		x = startx;
7228262685Sdelphij	if(starty != 0)
7229262685Sdelphij		y = starty;
7230262685Sdelphij	if(width == 0)
7231262685Sdelphij		width = 80;
7232166124Srafan
7233262685Sdelphij	length = strlen(string);
7234262685Sdelphij	temp = (width - length)/ 2;
7235262685Sdelphij	x = startx + (int)temp;
7236262685Sdelphij	wattron(win, color);
7237262685Sdelphij	mvwprintw(win, y, x, "%s", string);
7238262685Sdelphij	wattroff(win, color);
7239262685Sdelphij	refresh();
7240262685Sdelphij}</SPAN
7241262685Sdelphij></PRE
7242262685Sdelphij></DIV
7243262685Sdelphij></DIV
7244262685Sdelphij><DIV
7245262685SdelphijCLASS="SECT2"
7246262685Sdelphij><HR><H3
7247262685SdelphijCLASS="SECT2"
7248262685Sdelphij><A
7249262685SdelphijNAME="FILEDVALIDATE"
7250262685Sdelphij>18.5. Field Validation</A
7251262685Sdelphij></H3
7252262685Sdelphij><P
7253262685Sdelphij>By default, a field will accept any data input by the user. It is possible to
7254262685Sdelphijattach validation to the field. Then any attempt by the user to leave the field,
7255262685Sdelphijwhile it contains data that doesn't match the validation type will fail. Some
7256262685Sdelphijvalidation types also have a character-validity check for each time a character
7257262685Sdelphijis entered in the field.</P
7258262685Sdelphij><P
7259262685Sdelphij>Validation can be attached to a field with the following function.
7260262685Sdelphij<PRE
7261262685SdelphijCLASS="PROGRAMLISTING"
7262262685Sdelphij>int set_field_type(FIELD *field,          /* field to alter */
7263166124Srafan                   FIELDTYPE *ftype,      /* type to associate */
7264262685Sdelphij                   ...);                  /* additional arguments*/</PRE
7265262685Sdelphij>
7266166124SrafanOnce set, the validation type for a field can be queried with
7267262685Sdelphij<PRE
7268262685SdelphijCLASS="PROGRAMLISTING"
7269262685Sdelphij>FIELDTYPE *field_type(FIELD *field);      /* field to query */</PRE
7270262685Sdelphij></P
7271262685Sdelphij><P
7272262685Sdelphij>The form driver validates the data in a field only when data is entered by the
7273262685Sdelphijend-user. Validation does not occur when </P
7274262685Sdelphij><P
7275262685Sdelphij></P
7276262685Sdelphij><UL
7277262685Sdelphij><LI
7278262685Sdelphij><P
7279262685Sdelphij>the application program changes the field value by calling set_field_buffer. </P
7280262685Sdelphij></LI
7281262685Sdelphij><LI
7282262685Sdelphij><P
7283262685Sdelphij>linked field values are changed indirectly -- by changing the field to which
7284262685Sdelphijthey are linked</P
7285262685Sdelphij></LI
7286262685Sdelphij></UL
7287262685Sdelphij><P
7288262685Sdelphij>The following are the pre-defined validation types. You can also specify custom
7289262685Sdelphijvalidation, though it's a bit tricky and cumbersome.</P
7290262685Sdelphij><H1
7291262685SdelphijCLASS="BRIDGEHEAD"
7292262685Sdelphij><A
7293262685SdelphijNAME="AEN1069"
7294262685Sdelphij></A
7295262685Sdelphij>TYPE_ALPHA</H1
7296262685Sdelphij><P
7297262685Sdelphij>This field type accepts alphabetic data; no blanks, no digits, no special
7298262685Sdelphijcharacters (this is checked at character-entry time).  It is set up with: </P
7299262685Sdelphij><PRE
7300262685SdelphijCLASS="PROGRAMLISTING"
7301262685Sdelphij>int set_field_type(FIELD *field,          /* field to alter */
7302166124Srafan                   TYPE_ALPHA,            /* type to associate */
7303262685Sdelphij                   int width);            /* maximum width of field */</PRE
7304262685Sdelphij><P
7305262685Sdelphij>The width argument sets a minimum width of data. The user has to enter at-least
7306262685Sdelphijwidth number of characters before he can leave the field. Typically
7307262685Sdelphijyou'll want to set this to the field width; if it's greater than the
7308262685Sdelphijfield width, the validation check will always fail.  A minimum width
7309262685Sdelphijof zero makes field completion optional. </P
7310262685Sdelphij><H1
7311262685SdelphijCLASS="BRIDGEHEAD"
7312262685Sdelphij><A
7313262685SdelphijNAME="AEN1073"
7314262685Sdelphij></A
7315262685Sdelphij>TYPE_ALNUM</H1
7316262685Sdelphij><P
7317262685Sdelphij>This field type accepts alphabetic data and digits; no blanks, no special
7318262685Sdelphijcharacters (this is checked at character-entry time).  It is set up with: </P
7319262685Sdelphij><PRE
7320262685SdelphijCLASS="PROGRAMLISTING"
7321262685Sdelphij>int set_field_type(FIELD *field,          /* field to alter */
7322166124Srafan                   TYPE_ALNUM,            /* type to associate */
7323262685Sdelphij                   int width);            /* maximum width of field */</PRE
7324262685Sdelphij><P
7325262685Sdelphij>The width argument sets a minimum width of data.  As with
7326262685SdelphijTYPE_ALPHA, typically you'll want to set this to the field width; if it's
7327262685Sdelphijgreater than the field width, the validation check will always fail.  A
7328262685Sdelphijminimum width of zero makes field completion optional. </P
7329262685Sdelphij><H1
7330262685SdelphijCLASS="BRIDGEHEAD"
7331262685Sdelphij><A
7332262685SdelphijNAME="AEN1077"
7333262685Sdelphij></A
7334262685Sdelphij>TYPE_ENUM</H1
7335262685Sdelphij><P
7336262685Sdelphij>This type allows you to restrict a field's values to be among a specified
7337262685Sdelphijset of string values (for example, the two-letter postal codes for U.S.
7338262685Sdelphijstates).  It is set up with: </P
7339262685Sdelphij><PRE
7340262685SdelphijCLASS="PROGRAMLISTING"
7341262685Sdelphij>int set_field_type(FIELD *field,          /* field to alter */
7342166124Srafan                   TYPE_ENUM,             /* type to associate */
7343166124Srafan                   char **valuelist;      /* list of possible values */
7344166124Srafan                   int checkcase;         /* case-sensitive? */
7345262685Sdelphij                   int checkunique);      /* must specify uniquely? */</PRE
7346262685Sdelphij><P
7347262685Sdelphij>The valuelist parameter must point at a NULL-terminated list of
7348262685Sdelphijvalid strings.  The checkcase argument, if true, makes comparison
7349262685Sdelphijwith the string case-sensitive. </P
7350262685Sdelphij><P
7351262685Sdelphij>When the user exits a TYPE_ENUM field, the validation procedure tries to
7352262685Sdelphijcomplete the data in the buffer to a valid entry.  If a complete choice string
7353262685Sdelphijhas been entered, it is of course valid.  But it is also possible to enter a
7354262685Sdelphijprefix of a valid string and have it completed for you. </P
7355262685Sdelphij><P
7356262685Sdelphij>By default, if you enter such a prefix and it matches more than one value
7357262685Sdelphijin the string list, the prefix will be completed to the first matching
7358262685Sdelphijvalue.  But the checkunique argument, if true, requires prefix
7359262685Sdelphijmatches to be unique in order to be valid. </P
7360262685Sdelphij><P
7361262685Sdelphij>The REQ_NEXT_CHOICE and REQ_PREV_CHOICE input requests can be particularly
7362262685Sdelphijuseful with these fields. </P
7363262685Sdelphij><H1
7364262685SdelphijCLASS="BRIDGEHEAD"
7365262685Sdelphij><A
7366262685SdelphijNAME="AEN1084"
7367262685Sdelphij></A
7368262685Sdelphij>TYPE_INTEGER</H1
7369262685Sdelphij><P
7370262685Sdelphij>This field type accepts an integer.  It is set up as follows: </P
7371262685Sdelphij><PRE
7372262685SdelphijCLASS="PROGRAMLISTING"
7373262685Sdelphij>int set_field_type(FIELD *field,          /* field to alter */
7374166124Srafan                   TYPE_INTEGER,          /* type to associate */
7375166124Srafan                   int padding,           /* # places to zero-pad to */
7376262685Sdelphij                   int vmin, int vmax);   /* valid range */</PRE
7377262685Sdelphij><P
7378262685Sdelphij>Valid characters consist of an optional leading minus and digits.
7379262685SdelphijThe range check is performed on exit.  If the range maximum is less
7380262685Sdelphijthan or equal to the minimum, the range is ignored. </P
7381262685Sdelphij><P
7382262685Sdelphij>If the value passes its range check, it is padded with as many leading
7383262685Sdelphijzero digits as necessary to meet the padding argument. </P
7384262685Sdelphij><P
7385262685Sdelphij>A TYPE_INTEGER value buffer can conveniently be interpreted with the C library 
7386262685Sdelphijfunction atoi(3).</P
7387262685Sdelphij><H1
7388262685SdelphijCLASS="BRIDGEHEAD"
7389262685Sdelphij><A
7390262685SdelphijNAME="AEN1090"
7391262685Sdelphij></A
7392262685Sdelphij>TYPE_NUMERIC</H1
7393262685Sdelphij><P
7394262685Sdelphij>This field type accepts a decimal number.  It is set up as follows: </P
7395262685Sdelphij><PRE
7396262685SdelphijCLASS="PROGRAMLISTING"
7397262685Sdelphij>int set_field_type(FIELD *field,          /* field to alter */
7398166124Srafan                   TYPE_NUMERIC,          /* type to associate */
7399166124Srafan                   int padding,           /* # places of precision */
7400262685Sdelphij                   int vmin, int vmax);   /* valid range */</PRE
7401262685Sdelphij><P
7402262685Sdelphij>Valid characters consist of an optional leading minus and digits. possibly
7403262685Sdelphijincluding a decimal point.  The range check is performed on exit.  If the
7404262685Sdelphijrange maximum is less than or equal to the minimum, the range is
7405262685Sdelphijignored. </P
7406262685Sdelphij><P
7407262685Sdelphij>If the value passes its range check, it is padded with as many trailing
7408262685Sdelphijzero digits as necessary to meet the padding argument. </P
7409262685Sdelphij><P
7410262685Sdelphij>A TYPE_NUMERIC value buffer can conveniently be interpreted with the C library 
7411262685Sdelphijfunction atof(3).</P
7412262685Sdelphij><H1
7413262685SdelphijCLASS="BRIDGEHEAD"
7414262685Sdelphij><A
7415262685SdelphijNAME="AEN1096"
7416262685Sdelphij></A
7417262685Sdelphij>TYPE_REGEXP</H1
7418262685Sdelphij><P
7419262685Sdelphij>This field type accepts data matching a regular expression.  It is set up
7420262685Sdelphijas follows: </P
7421262685Sdelphij><PRE
7422262685SdelphijCLASS="PROGRAMLISTING"
7423262685Sdelphij>int set_field_type(FIELD *field,          /* field to alter */
7424166124Srafan                   TYPE_REGEXP,           /* type to associate */
7425262685Sdelphij                   char *regexp);         /* expression to match */</PRE
7426262685Sdelphij><P
7427262685Sdelphij>The syntax for regular expressions is that of regcomp(3).
7428262685SdelphijThe check for regular-expression match is performed on exit.</P
7429262685Sdelphij></DIV
7430262685Sdelphij><DIV
7431262685SdelphijCLASS="SECT2"
7432262685Sdelphij><HR><H3
7433262685SdelphijCLASS="SECT2"
7434262685Sdelphij><A
7435262685SdelphijNAME="FORMDRIVER"
7436262685Sdelphij>18.6. Form Driver: The work horse of the forms system</A
7437262685Sdelphij></H3
7438262685Sdelphij><P
7439262685Sdelphij>As in the menu system, form_driver() plays a very important role in forms
7440262685Sdelphijsystem.  All types of requests to forms system should be funneled through
7441262685Sdelphijform_driver().</P
7442262685Sdelphij><PRE
7443262685SdelphijCLASS="PROGRAMLISTING"
7444262685Sdelphij>int form_driver(FORM *form,     /* form on which to operate     */
7445262685Sdelphij                int request)    /* form request code         */</PRE
7446262685Sdelphij><P
7447262685Sdelphij>As you have seen some of the examples above, you have to be in a loop looking
7448262685Sdelphijfor user input and then decide whether it's a field data or a form request. The
7449262685Sdelphijform requests are then passed to form_driver() to do the work.</P
7450262685Sdelphij><P
7451262685Sdelphij>The requests roughly can be divided into following categories. Different
7452262685Sdelphijrequests and their usage is explained below:</P
7453262685Sdelphij><DIV
7454262685SdelphijCLASS="SECT3"
7455262685Sdelphij><HR><H4
7456262685SdelphijCLASS="SECT3"
7457262685Sdelphij><A
7458262685SdelphijNAME="PAGENAVREQ"
7459262685Sdelphij>18.6.1. Page Navigation Requests</A
7460262685Sdelphij></H4
7461262685Sdelphij><P
7462262685Sdelphij>These requests cause page-level moves through the form, triggering display of a
7463262685Sdelphijnew form screen. A form can be made of multiple pages. If you have a big form
7464262685Sdelphijwith lot of fields and logical sections, then you can divide the form into
7465262685Sdelphijpages. The function set_new_page() to set a new page at the field specified.</P
7466262685Sdelphij><PRE
7467262685SdelphijCLASS="PROGRAMLISTING"
7468262685Sdelphij>int set_new_page(FIELD *field,/* Field at which page break to be set or unset */
7469262685Sdelphij         bool new_page_flag); /* should be TRUE to put a break */</PRE
7470262685Sdelphij><P
7471262685Sdelphij>The following requests allow you to move to different pages</P
7472262685Sdelphij><P
7473262685Sdelphij></P
7474262685Sdelphij><UL
7475262685Sdelphij><LI
7476262685Sdelphij><P
7477262685Sdelphij><SPAN
7478262685SdelphijCLASS="emphasis"
7479262685Sdelphij><I
7480262685SdelphijCLASS="EMPHASIS"
7481262685Sdelphij>REQ_NEXT_PAGE</I
7482262685Sdelphij></SPAN
7483262685Sdelphij> Move to the next form page.</P
7484262685Sdelphij></LI
7485262685Sdelphij><LI
7486262685Sdelphij><P
7487262685Sdelphij><SPAN
7488262685SdelphijCLASS="emphasis"
7489262685Sdelphij><I
7490262685SdelphijCLASS="EMPHASIS"
7491262685Sdelphij>REQ_PREV_PAGE</I
7492262685Sdelphij></SPAN
7493262685Sdelphij> Move to the previous
7494262685Sdelphijform page.</P
7495262685Sdelphij></LI
7496262685Sdelphij><LI
7497262685Sdelphij><P
7498262685Sdelphij><SPAN
7499262685SdelphijCLASS="emphasis"
7500262685Sdelphij><I
7501262685SdelphijCLASS="EMPHASIS"
7502262685Sdelphij>REQ_FIRST_PAGE</I
7503262685Sdelphij></SPAN
7504262685Sdelphij> Move to the first form page.</P
7505262685Sdelphij></LI
7506262685Sdelphij><LI
7507262685Sdelphij><P
7508262685Sdelphij><SPAN
7509262685SdelphijCLASS="emphasis"
7510262685Sdelphij><I
7511262685SdelphijCLASS="EMPHASIS"
7512262685Sdelphij>REQ_LAST_PAGE</I
7513262685Sdelphij></SPAN
7514262685Sdelphij> Move to the last form page. </P
7515262685Sdelphij></LI
7516262685Sdelphij></UL
7517262685Sdelphij><P
7518262685Sdelphij>These requests treat the list as cyclic; that is, REQ_NEXT_PAGE from the
7519262685Sdelphijlast page goes to the first, and REQ_PREV_PAGE from the first page goes to
7520262685Sdelphijthe last.</P
7521262685Sdelphij></DIV
7522262685Sdelphij><DIV
7523262685SdelphijCLASS="SECT3"
7524262685Sdelphij><HR><H4
7525262685SdelphijCLASS="SECT3"
7526262685Sdelphij><A
7527262685SdelphijNAME="INTERFIELDNAVREQ"
7528262685Sdelphij>18.6.2. Inter-Field Navigation Requests</A
7529262685Sdelphij></H4
7530262685Sdelphij><P
7531262685Sdelphij>These requests handle navigation between fields on the same page.</P
7532262685Sdelphij><P
7533262685Sdelphij></P
7534262685Sdelphij><UL
7535262685Sdelphij><LI
7536262685Sdelphij><P
7537262685Sdelphij><SPAN
7538262685SdelphijCLASS="emphasis"
7539262685Sdelphij><I
7540262685SdelphijCLASS="EMPHASIS"
7541262685Sdelphij>REQ_NEXT_FIELD</I
7542262685Sdelphij></SPAN
7543262685Sdelphij> 
7544262685Sdelphij    Move to next field.  </P
7545262685Sdelphij></LI
7546262685Sdelphij><LI
7547262685Sdelphij><P
7548262685Sdelphij><SPAN
7549262685SdelphijCLASS="emphasis"
7550262685Sdelphij><I
7551262685SdelphijCLASS="EMPHASIS"
7552262685Sdelphij>REQ_PREV_FIELD</I
7553262685Sdelphij></SPAN
7554262685Sdelphij>
7555262685Sdelphij    Move to previous field.  </P
7556262685Sdelphij></LI
7557262685Sdelphij><LI
7558262685Sdelphij><P
7559262685Sdelphij><SPAN
7560262685SdelphijCLASS="emphasis"
7561262685Sdelphij><I
7562262685SdelphijCLASS="EMPHASIS"
7563262685Sdelphij>REQ_FIRST_FIELD</I
7564262685Sdelphij></SPAN
7565262685Sdelphij>
7566262685Sdelphij    Move to the first field. </P
7567262685Sdelphij></LI
7568262685Sdelphij><LI
7569262685Sdelphij><P
7570262685Sdelphij><SPAN
7571262685SdelphijCLASS="emphasis"
7572262685Sdelphij><I
7573262685SdelphijCLASS="EMPHASIS"
7574262685Sdelphij>REQ_LAST_FIELD</I
7575262685Sdelphij></SPAN
7576262685Sdelphij> 
7577262685Sdelphij    Move to the last field. </P
7578262685Sdelphij></LI
7579262685Sdelphij><LI
7580262685Sdelphij><P
7581262685Sdelphij><SPAN
7582262685SdelphijCLASS="emphasis"
7583262685Sdelphij><I
7584262685SdelphijCLASS="EMPHASIS"
7585262685Sdelphij>REQ_SNEXT_FIELD</I
7586262685Sdelphij></SPAN
7587262685Sdelphij>
7588262685Sdelphij    Move to sorted next field. </P
7589262685Sdelphij></LI
7590262685Sdelphij><LI
7591262685Sdelphij><P
7592262685Sdelphij><SPAN
7593262685SdelphijCLASS="emphasis"
7594262685Sdelphij><I
7595262685SdelphijCLASS="EMPHASIS"
7596262685Sdelphij>REQ_SPREV_FIELD</I
7597262685Sdelphij></SPAN
7598262685Sdelphij> 
7599262685Sdelphij    Move to sorted previous field. </P
7600262685Sdelphij></LI
7601262685Sdelphij><LI
7602262685Sdelphij><P
7603262685Sdelphij><SPAN
7604262685SdelphijCLASS="emphasis"
7605262685Sdelphij><I
7606262685SdelphijCLASS="EMPHASIS"
7607262685Sdelphij>REQ_SFIRST_FIELD</I
7608262685Sdelphij></SPAN
7609262685Sdelphij>
7610262685Sdelphij    Move to the sorted first field. </P
7611262685Sdelphij></LI
7612262685Sdelphij><LI
7613262685Sdelphij><P
7614262685Sdelphij><SPAN
7615262685SdelphijCLASS="emphasis"
7616262685Sdelphij><I
7617262685SdelphijCLASS="EMPHASIS"
7618262685Sdelphij>REQ_SLAST_FIELD</I
7619262685Sdelphij></SPAN
7620262685Sdelphij>
7621262685Sdelphij    Move to the sorted last field. </P
7622262685Sdelphij></LI
7623262685Sdelphij><LI
7624262685Sdelphij><P
7625262685Sdelphij><SPAN
7626262685SdelphijCLASS="emphasis"
7627262685Sdelphij><I
7628262685SdelphijCLASS="EMPHASIS"
7629262685Sdelphij>REQ_LEFT_FIELD</I
7630262685Sdelphij></SPAN
7631262685Sdelphij>
7632262685Sdelphij    Move left to field.  </P
7633262685Sdelphij></LI
7634262685Sdelphij><LI
7635262685Sdelphij><P
7636262685Sdelphij><SPAN
7637262685SdelphijCLASS="emphasis"
7638262685Sdelphij><I
7639262685SdelphijCLASS="EMPHASIS"
7640262685Sdelphij>REQ_RIGHT_FIELD</I
7641262685Sdelphij></SPAN
7642262685Sdelphij>
7643262685Sdelphij    Move right to field. </P
7644262685Sdelphij></LI
7645262685Sdelphij><LI
7646262685Sdelphij><P
7647262685Sdelphij><SPAN
7648262685SdelphijCLASS="emphasis"
7649262685Sdelphij><I
7650262685SdelphijCLASS="EMPHASIS"
7651262685Sdelphij>REQ_UP_FIELD</I
7652262685Sdelphij></SPAN
7653262685Sdelphij>
7654262685Sdelphij    Move up to field.  </P
7655262685Sdelphij></LI
7656262685Sdelphij><LI
7657262685Sdelphij><P
7658262685Sdelphij><SPAN
7659262685SdelphijCLASS="emphasis"
7660262685Sdelphij><I
7661262685SdelphijCLASS="EMPHASIS"
7662262685Sdelphij>REQ_DOWN_FIELD</I
7663262685Sdelphij></SPAN
7664262685Sdelphij>
7665262685Sdelphij    Move down to field. </P
7666262685Sdelphij></LI
7667262685Sdelphij></UL
7668262685Sdelphij><P
7669262685Sdelphij>These requests treat the list of fields on a page as cyclic; that is,
7670262685SdelphijREQ_NEXT_FIELD from the last field goes to the first, and REQ_PREV_FIELD
7671262685Sdelphijfrom the first field goes to the last. The order of the fields for these
7672262685Sdelphij(and the REQ_FIRST_FIELD and REQ_LAST_FIELD requests) is simply the order of
7673262685Sdelphijthe field pointers in the form array (as set up by new_form() or
7674262685Sdelphijset_form_fields()</P
7675262685Sdelphij><P
7676262685Sdelphij>It is also possible to traverse the fields as if they had been sorted in
7677262685Sdelphijscreen-position order, so the sequence goes left-to-right and top-to-bottom.
7678262685SdelphijTo do this, use the second group of four sorted-movement requests.</P
7679262685Sdelphij><P
7680262685Sdelphij>Finally, it is possible to move between fields using visual directions up,
7681262685Sdelphijdown, right, and left. To accomplish this, use the third group of four
7682262685Sdelphijrequests. Note, however, that the position of a form for purposes of these
7683262685Sdelphijrequests is its upper-left corner.</P
7684262685Sdelphij><P
7685262685Sdelphij>For example, suppose you have a multi-line field B, and two single-line
7686262685Sdelphijfields A and C on the same line with B, with A to the left of B and C to the
7687262685Sdelphijright of B. A REQ_MOVE_RIGHT from A will go to B only if A, B, and C all
7688262685Sdelphijshare the same first line; otherwise it will skip over B to C.</P
7689262685Sdelphij></DIV
7690262685Sdelphij><DIV
7691262685SdelphijCLASS="SECT3"
7692262685Sdelphij><HR><H4
7693262685SdelphijCLASS="SECT3"
7694262685Sdelphij><A
7695262685SdelphijNAME="INTRAFIELDNAVREQ"
7696262685Sdelphij>18.6.3. Intra-Field Navigation Requests</A
7697262685Sdelphij></H4
7698262685Sdelphij><P
7699262685Sdelphij>These requests drive movement of the edit cursor within the currently
7700262685Sdelphijselected field.</P
7701262685Sdelphij><P
7702262685Sdelphij></P
7703262685Sdelphij><UL
7704262685Sdelphij><LI
7705262685Sdelphij><P
7706262685Sdelphij><SPAN
7707262685SdelphijCLASS="emphasis"
7708262685Sdelphij><I
7709262685SdelphijCLASS="EMPHASIS"
7710262685Sdelphij>REQ_NEXT_CHAR</I
7711262685Sdelphij></SPAN
7712262685Sdelphij>
7713262685Sdelphij    Move to next character.  </P
7714262685Sdelphij></LI
7715262685Sdelphij><LI
7716262685Sdelphij><P
7717262685Sdelphij><SPAN
7718262685SdelphijCLASS="emphasis"
7719262685Sdelphij><I
7720262685SdelphijCLASS="EMPHASIS"
7721262685Sdelphij>REQ_PREV_CHAR</I
7722262685Sdelphij></SPAN
7723262685Sdelphij> 
7724262685Sdelphij    Move to previous character.  </P
7725262685Sdelphij></LI
7726262685Sdelphij><LI
7727262685Sdelphij><P
7728262685Sdelphij><SPAN
7729262685SdelphijCLASS="emphasis"
7730262685Sdelphij><I
7731262685SdelphijCLASS="EMPHASIS"
7732262685Sdelphij>REQ_NEXT_LINE</I
7733262685Sdelphij></SPAN
7734262685Sdelphij> 
7735262685Sdelphij    Move to next line.  </P
7736262685Sdelphij></LI
7737262685Sdelphij><LI
7738262685Sdelphij><P
7739262685Sdelphij><SPAN
7740262685SdelphijCLASS="emphasis"
7741262685Sdelphij><I
7742262685SdelphijCLASS="EMPHASIS"
7743262685Sdelphij>REQ_PREV_LINE</I
7744262685Sdelphij></SPAN
7745262685Sdelphij> 
7746262685Sdelphij    Move to previous line.  </P
7747262685Sdelphij></LI
7748262685Sdelphij><LI
7749262685Sdelphij><P
7750262685Sdelphij><SPAN
7751262685SdelphijCLASS="emphasis"
7752262685Sdelphij><I
7753262685SdelphijCLASS="EMPHASIS"
7754262685Sdelphij>REQ_NEXT_WORD</I
7755262685Sdelphij></SPAN
7756262685Sdelphij> 
7757262685Sdelphij    Move to next word. </P
7758262685Sdelphij></LI
7759262685Sdelphij><LI
7760262685Sdelphij><P
7761262685Sdelphij><SPAN
7762262685SdelphijCLASS="emphasis"
7763262685Sdelphij><I
7764262685SdelphijCLASS="EMPHASIS"
7765262685Sdelphij>REQ_PREV_WORD</I
7766262685Sdelphij></SPAN
7767262685Sdelphij>
7768262685Sdelphij    Move to previous word. </P
7769262685Sdelphij></LI
7770262685Sdelphij><LI
7771262685Sdelphij><P
7772262685Sdelphij><SPAN
7773262685SdelphijCLASS="emphasis"
7774262685Sdelphij><I
7775262685SdelphijCLASS="EMPHASIS"
7776262685Sdelphij>REQ_BEG_FIELD</I
7777262685Sdelphij></SPAN
7778262685Sdelphij>
7779262685Sdelphij    Move to beginning of field. </P
7780262685Sdelphij></LI
7781262685Sdelphij><LI
7782262685Sdelphij><P
7783262685Sdelphij><SPAN
7784262685SdelphijCLASS="emphasis"
7785262685Sdelphij><I
7786262685SdelphijCLASS="EMPHASIS"
7787262685Sdelphij>REQ_END_FIELD</I
7788262685Sdelphij></SPAN
7789262685Sdelphij>
7790262685Sdelphij    Move to end of field. </P
7791262685Sdelphij></LI
7792262685Sdelphij><LI
7793262685Sdelphij><P
7794262685Sdelphij><SPAN
7795262685SdelphijCLASS="emphasis"
7796262685Sdelphij><I
7797262685SdelphijCLASS="EMPHASIS"
7798262685Sdelphij>REQ_BEG_LINE</I
7799262685Sdelphij></SPAN
7800262685Sdelphij>
7801262685Sdelphij    Move to beginning of line. </P
7802262685Sdelphij></LI
7803262685Sdelphij><LI
7804262685Sdelphij><P
7805262685Sdelphij><SPAN
7806262685SdelphijCLASS="emphasis"
7807262685Sdelphij><I
7808262685SdelphijCLASS="EMPHASIS"
7809262685Sdelphij>REQ_END_LINE</I
7810262685Sdelphij></SPAN
7811262685Sdelphij>
7812262685Sdelphij    Move to end of line.  </P
7813262685Sdelphij></LI
7814262685Sdelphij><LI
7815262685Sdelphij><P
7816262685Sdelphij><SPAN
7817262685SdelphijCLASS="emphasis"
7818262685Sdelphij><I
7819262685SdelphijCLASS="EMPHASIS"
7820262685Sdelphij>REQ_LEFT_CHAR</I
7821262685Sdelphij></SPAN
7822262685Sdelphij> 
7823262685Sdelphij    Move left in field. </P
7824262685Sdelphij></LI
7825262685Sdelphij><LI
7826262685Sdelphij><P
7827262685Sdelphij><SPAN
7828262685SdelphijCLASS="emphasis"
7829262685Sdelphij><I
7830262685SdelphijCLASS="EMPHASIS"
7831262685Sdelphij>REQ_RIGHT_CHAR</I
7832262685Sdelphij></SPAN
7833262685Sdelphij>
7834262685Sdelphij    Move right in field.  </P
7835262685Sdelphij></LI
7836262685Sdelphij><LI
7837262685Sdelphij><P
7838262685Sdelphij><SPAN
7839262685SdelphijCLASS="emphasis"
7840262685Sdelphij><I
7841262685SdelphijCLASS="EMPHASIS"
7842262685Sdelphij>REQ_UP_CHAR</I
7843262685Sdelphij></SPAN
7844262685Sdelphij>
7845262685Sdelphij    Move up in field. </P
7846262685Sdelphij></LI
7847262685Sdelphij><LI
7848262685Sdelphij><P
7849262685Sdelphij><SPAN
7850262685SdelphijCLASS="emphasis"
7851262685Sdelphij><I
7852262685SdelphijCLASS="EMPHASIS"
7853262685Sdelphij>REQ_DOWN_CHAR</I
7854262685Sdelphij></SPAN
7855262685Sdelphij> 
7856262685Sdelphij    Move down in field. </P
7857262685Sdelphij></LI
7858262685Sdelphij></UL
7859262685Sdelphij><P
7860262685Sdelphij>Each word is separated from the previous and next characters by whitespace.
7861262685SdelphijThe commands to move to beginning and end of line or field look for the
7862262685Sdelphijfirst or last non-pad character in their ranges.</P
7863262685Sdelphij></DIV
7864262685Sdelphij><DIV
7865262685SdelphijCLASS="SECT3"
7866262685Sdelphij><HR><H4
7867262685SdelphijCLASS="SECT3"
7868262685Sdelphij><A
7869262685SdelphijNAME="SCROLLREQ"
7870262685Sdelphij>18.6.4. Scrolling Requests</A
7871262685Sdelphij></H4
7872262685Sdelphij><P
7873262685Sdelphij>Fields that are dynamic and have grown and fields explicitly created with
7874262685Sdelphijoffscreen rows are scrollable. One-line fields scroll horizontally;
7875262685Sdelphijmulti-line fields scroll vertically. Most scrolling is triggered by editing
7876262685Sdelphijand intra-field movement (the library scrolls the field to keep the cursor
7877262685Sdelphijvisible). It is possible to explicitly request scrolling with the following
7878262685Sdelphijrequests:</P
7879262685Sdelphij><P
7880262685Sdelphij></P
7881262685Sdelphij><UL
7882262685Sdelphij><LI
7883262685Sdelphij><P
7884262685Sdelphij><SPAN
7885262685SdelphijCLASS="emphasis"
7886262685Sdelphij><I
7887262685SdelphijCLASS="EMPHASIS"
7888262685Sdelphij>REQ_SCR_FLINE</I
7889262685Sdelphij></SPAN
7890262685Sdelphij>
7891262685Sdelphij    Scroll vertically forward a line.  </P
7892262685Sdelphij></LI
7893262685Sdelphij><LI
7894262685Sdelphij><P
7895262685Sdelphij><SPAN
7896262685SdelphijCLASS="emphasis"
7897262685Sdelphij><I
7898262685SdelphijCLASS="EMPHASIS"
7899262685Sdelphij>REQ_SCR_BLINE</I
7900262685Sdelphij></SPAN
7901262685Sdelphij> 
7902262685Sdelphij    Scroll vertically backward a line.  </P
7903262685Sdelphij></LI
7904262685Sdelphij><LI
7905262685Sdelphij><P
7906262685Sdelphij><SPAN
7907262685SdelphijCLASS="emphasis"
7908262685Sdelphij><I
7909262685SdelphijCLASS="EMPHASIS"
7910262685Sdelphij>REQ_SCR_FPAGE</I
7911262685Sdelphij></SPAN
7912262685Sdelphij> 
7913262685Sdelphij    Scroll vertically forward a page.  </P
7914262685Sdelphij></LI
7915262685Sdelphij><LI
7916262685Sdelphij><P
7917262685Sdelphij><SPAN
7918262685SdelphijCLASS="emphasis"
7919262685Sdelphij><I
7920262685SdelphijCLASS="EMPHASIS"
7921262685Sdelphij>REQ_SCR_BPAGE</I
7922262685Sdelphij></SPAN
7923262685Sdelphij>
7924262685Sdelphij    Scroll vertically backward a page. </P
7925262685Sdelphij></LI
7926262685Sdelphij><LI
7927262685Sdelphij><P
7928262685Sdelphij><SPAN
7929262685SdelphijCLASS="emphasis"
7930262685Sdelphij><I
7931262685SdelphijCLASS="EMPHASIS"
7932262685Sdelphij>REQ_SCR_FHPAGE</I
7933262685Sdelphij></SPAN
7934262685Sdelphij>
7935262685Sdelphij    Scroll vertically forward half a page. </P
7936262685Sdelphij></LI
7937262685Sdelphij><LI
7938262685Sdelphij><P
7939262685Sdelphij><SPAN
7940262685SdelphijCLASS="emphasis"
7941262685Sdelphij><I
7942262685SdelphijCLASS="EMPHASIS"
7943262685Sdelphij>REQ_SCR_BHPAGE</I
7944262685Sdelphij></SPAN
7945262685Sdelphij>
7946262685Sdelphij    Scroll vertically backward half a page. </P
7947262685Sdelphij></LI
7948262685Sdelphij><LI
7949262685Sdelphij><P
7950262685Sdelphij><SPAN
7951262685SdelphijCLASS="emphasis"
7952262685Sdelphij><I
7953262685SdelphijCLASS="EMPHASIS"
7954262685Sdelphij>REQ_SCR_FCHAR</I
7955262685Sdelphij></SPAN
7956262685Sdelphij>
7957262685Sdelphij    Scroll horizontally forward a character. </P
7958262685Sdelphij></LI
7959262685Sdelphij><LI
7960262685Sdelphij><P
7961262685Sdelphij><SPAN
7962262685SdelphijCLASS="emphasis"
7963262685Sdelphij><I
7964262685SdelphijCLASS="EMPHASIS"
7965262685Sdelphij>REQ_SCR_BCHAR</I
7966262685Sdelphij></SPAN
7967262685Sdelphij>
7968262685Sdelphij    Scroll horizontally backward a character. </P
7969262685Sdelphij></LI
7970262685Sdelphij><LI
7971262685Sdelphij><P
7972262685Sdelphij><SPAN
7973262685SdelphijCLASS="emphasis"
7974262685Sdelphij><I
7975262685SdelphijCLASS="EMPHASIS"
7976262685Sdelphij>REQ_SCR_HFLINE</I
7977262685Sdelphij></SPAN
7978262685Sdelphij>
7979262685Sdelphij    Scroll horizontally one field width forward. </P
7980262685Sdelphij></LI
7981262685Sdelphij><LI
7982262685Sdelphij><P
7983262685Sdelphij><SPAN
7984262685SdelphijCLASS="emphasis"
7985262685Sdelphij><I
7986262685SdelphijCLASS="EMPHASIS"
7987262685Sdelphij>REQ_SCR_HBLINE</I
7988262685Sdelphij></SPAN
7989262685Sdelphij>
7990262685Sdelphij    Scroll horizontally one field width backward. </P
7991262685Sdelphij></LI
7992262685Sdelphij><LI
7993262685Sdelphij><P
7994262685Sdelphij><SPAN
7995262685SdelphijCLASS="emphasis"
7996262685Sdelphij><I
7997262685SdelphijCLASS="EMPHASIS"
7998262685Sdelphij>REQ_SCR_HFHALF</I
7999262685Sdelphij></SPAN
8000262685Sdelphij>
8001262685Sdelphij    Scroll horizontally one half field width forward. </P
8002262685Sdelphij></LI
8003262685Sdelphij><LI
8004262685Sdelphij><P
8005262685Sdelphij><SPAN
8006262685SdelphijCLASS="emphasis"
8007262685Sdelphij><I
8008262685SdelphijCLASS="EMPHASIS"
8009262685Sdelphij>REQ_SCR_HBHALF</I
8010262685Sdelphij></SPAN
8011262685Sdelphij>
8012262685Sdelphij    Scroll horizontally one half field width backward. </P
8013262685Sdelphij></LI
8014262685Sdelphij></UL
8015262685Sdelphij><P
8016262685Sdelphij>For scrolling purposes, a page of a field is the height of its visible part.</P
8017262685Sdelphij></DIV
8018262685Sdelphij><DIV
8019262685SdelphijCLASS="SECT3"
8020262685Sdelphij><HR><H4
8021262685SdelphijCLASS="SECT3"
8022262685Sdelphij><A
8023262685SdelphijNAME="EDITREQ"
8024262685Sdelphij>18.6.5. Editing Requests</A
8025262685Sdelphij></H4
8026262685Sdelphij><P
8027262685Sdelphij>When you pass the forms driver an ASCII character, it is treated as a
8028262685Sdelphijrequest to add the character to the field's data buffer. Whether this is an
8029262685Sdelphijinsertion or a replacement depends on the field's edit mode (insertion is
8030262685Sdelphijthe default.</P
8031262685Sdelphij><P
8032262685Sdelphij>The following requests support editing the field and changing the edit mode:</P
8033262685Sdelphij><P
8034262685Sdelphij></P
8035262685Sdelphij><UL
8036262685Sdelphij><LI
8037262685Sdelphij><P
8038262685Sdelphij><SPAN
8039262685SdelphijCLASS="emphasis"
8040262685Sdelphij><I
8041262685SdelphijCLASS="EMPHASIS"
8042262685Sdelphij>REQ_INS_MODE</I
8043262685Sdelphij></SPAN
8044262685Sdelphij> 
8045262685Sdelphij    Set insertion mode. </P
8046262685Sdelphij></LI
8047262685Sdelphij><LI
8048262685Sdelphij><P
8049262685Sdelphij><SPAN
8050262685SdelphijCLASS="emphasis"
8051262685Sdelphij><I
8052262685SdelphijCLASS="EMPHASIS"
8053262685Sdelphij>REQ_OVL_MODE</I
8054262685Sdelphij></SPAN
8055262685Sdelphij> 
8056262685Sdelphij    Set overlay mode. </P
8057262685Sdelphij></LI
8058262685Sdelphij><LI
8059262685Sdelphij><P
8060262685Sdelphij><SPAN
8061262685SdelphijCLASS="emphasis"
8062262685Sdelphij><I
8063262685SdelphijCLASS="EMPHASIS"
8064262685Sdelphij>REQ_NEW_LINE</I
8065262685Sdelphij></SPAN
8066262685Sdelphij> 
8067262685Sdelphij    New line request (see below for explanation). </P
8068262685Sdelphij></LI
8069262685Sdelphij><LI
8070262685Sdelphij><P
8071262685Sdelphij><SPAN
8072262685SdelphijCLASS="emphasis"
8073262685Sdelphij><I
8074262685SdelphijCLASS="EMPHASIS"
8075262685Sdelphij>REQ_INS_CHAR</I
8076262685Sdelphij></SPAN
8077262685Sdelphij>
8078262685Sdelphij    Insert space at character location.  </P
8079262685Sdelphij></LI
8080262685Sdelphij><LI
8081262685Sdelphij><P
8082262685Sdelphij><SPAN
8083262685SdelphijCLASS="emphasis"
8084262685Sdelphij><I
8085262685SdelphijCLASS="EMPHASIS"
8086262685Sdelphij>REQ_INS_LINE</I
8087262685Sdelphij></SPAN
8088262685Sdelphij>
8089262685Sdelphij    Insert blank line at character location.  </P
8090262685Sdelphij></LI
8091262685Sdelphij><LI
8092262685Sdelphij><P
8093262685Sdelphij><SPAN
8094262685SdelphijCLASS="emphasis"
8095262685Sdelphij><I
8096262685SdelphijCLASS="EMPHASIS"
8097262685Sdelphij>REQ_DEL_CHAR</I
8098262685Sdelphij></SPAN
8099262685Sdelphij>
8100262685Sdelphij    Delete character at cursor.  </P
8101262685Sdelphij></LI
8102262685Sdelphij><LI
8103262685Sdelphij><P
8104262685Sdelphij><SPAN
8105262685SdelphijCLASS="emphasis"
8106262685Sdelphij><I
8107262685SdelphijCLASS="EMPHASIS"
8108262685Sdelphij>REQ_DEL_PREV</I
8109262685Sdelphij></SPAN
8110262685Sdelphij> 
8111262685Sdelphij    Delete previous word at cursor. </P
8112262685Sdelphij></LI
8113262685Sdelphij><LI
8114262685Sdelphij><P
8115262685Sdelphij><SPAN
8116262685SdelphijCLASS="emphasis"
8117262685Sdelphij><I
8118262685SdelphijCLASS="EMPHASIS"
8119262685Sdelphij>REQ_DEL_LINE</I
8120262685Sdelphij></SPAN
8121262685Sdelphij>
8122262685Sdelphij    Delete line at cursor. </P
8123262685Sdelphij></LI
8124262685Sdelphij><LI
8125262685Sdelphij><P
8126262685Sdelphij><SPAN
8127262685SdelphijCLASS="emphasis"
8128262685Sdelphij><I
8129262685SdelphijCLASS="EMPHASIS"
8130262685Sdelphij>REQ_DEL_WORD</I
8131262685Sdelphij></SPAN
8132262685Sdelphij>
8133262685Sdelphij    Delete word at cursor. </P
8134262685Sdelphij></LI
8135262685Sdelphij><LI
8136262685Sdelphij><P
8137262685Sdelphij><SPAN
8138262685SdelphijCLASS="emphasis"
8139262685Sdelphij><I
8140262685SdelphijCLASS="EMPHASIS"
8141262685Sdelphij>REQ_CLR_EOL</I
8142262685Sdelphij></SPAN
8143262685Sdelphij>
8144262685Sdelphij    Clear to end of line. </P
8145262685Sdelphij></LI
8146262685Sdelphij><LI
8147262685Sdelphij><P
8148262685Sdelphij><SPAN
8149262685SdelphijCLASS="emphasis"
8150262685Sdelphij><I
8151262685SdelphijCLASS="EMPHASIS"
8152262685Sdelphij>REQ_CLR_EOF</I
8153262685Sdelphij></SPAN
8154262685Sdelphij>
8155262685Sdelphij    Clear to end of field. </P
8156262685Sdelphij></LI
8157262685Sdelphij><LI
8158262685Sdelphij><P
8159262685Sdelphij><SPAN
8160262685SdelphijCLASS="emphasis"
8161262685Sdelphij><I
8162262685SdelphijCLASS="EMPHASIS"
8163262685Sdelphij>REQ_CLR_FIELD</I
8164262685Sdelphij></SPAN
8165262685Sdelphij>
8166262685Sdelphij    Clear entire field. </P
8167262685Sdelphij></LI
8168262685Sdelphij></UL
8169262685Sdelphij><P
8170262685Sdelphij>The behavior of the REQ_NEW_LINE and REQ_DEL_PREV requests is complicated
8171262685Sdelphijand partly controlled by a pair of forms options. The special cases are
8172262685Sdelphijtriggered when the cursor is at the beginning of a field, or on the last
8173262685Sdelphijline of the field.</P
8174262685Sdelphij><P
8175262685Sdelphij>First, we consider REQ_NEW_LINE:</P
8176262685Sdelphij><P
8177262685Sdelphij>The normal behavior of REQ_NEW_LINE in insert mode is to break the current
8178262685Sdelphijline at the position of the edit cursor, inserting the portion of the
8179262685Sdelphijcurrent line after the cursor as a new line following the current and moving
8180262685Sdelphijthe cursor to the beginning of that new line (you may think of this as
8181262685Sdelphijinserting a newline in the field buffer).</P
8182262685Sdelphij><P
8183262685Sdelphij>The normal behavior of REQ_NEW_LINE in overlay mode is to clear the current
8184262685Sdelphijline from the position of the edit cursor to end of line. The cursor is then
8185262685Sdelphijmoved to the beginning of the next line.</P
8186262685Sdelphij><P
8187262685Sdelphij>However, REQ_NEW_LINE at the beginning of a field, or on the last line of a
8188262685Sdelphijfield, instead does a REQ_NEXT_FIELD. O_NL_OVERLOAD option is off, this
8189262685Sdelphijspecial action is disabled.</P
8190262685Sdelphij><P
8191262685Sdelphij>Now, let us consider REQ_DEL_PREV:</P
8192262685Sdelphij><P
8193262685Sdelphij>The normal behavior of REQ_DEL_PREV is to delete the previous character. If
8194262685Sdelphijinsert mode is on, and the cursor is at the start of a line, and the text on
8195262685Sdelphijthat line will fit on the previous one, it instead appends the contents of
8196262685Sdelphijthe current line to the previous one and deletes the current line (you may
8197262685Sdelphijthink of this as deleting a newline from the field buffer).</P
8198262685Sdelphij><P
8199262685Sdelphij>However, REQ_DEL_PREV at the beginning of a field is instead treated as a
8200262685SdelphijREQ_PREV_FIELD.</P
8201262685Sdelphij><P
8202262685Sdelphij>If the O_BS_OVERLOAD option is off, this special action is disabled and the
8203262685Sdelphijforms driver just returns E_REQUEST_DENIED.</P
8204262685Sdelphij></DIV
8205262685Sdelphij><DIV
8206262685SdelphijCLASS="SECT3"
8207262685Sdelphij><HR><H4
8208262685SdelphijCLASS="SECT3"
8209262685Sdelphij><A
8210262685SdelphijNAME="ORDERREQ"
8211262685Sdelphij>18.6.6. Order Requests</A
8212262685Sdelphij></H4
8213262685Sdelphij><P
8214262685Sdelphij>If the type of your field is ordered, and has associated functions for
8215262685Sdelphijgetting the next and previous values of the type from a given value, there
8216262685Sdelphijare requests that can fetch that value into the field buffer:</P
8217262685Sdelphij><P
8218262685Sdelphij></P
8219262685Sdelphij><UL
8220262685Sdelphij><LI
8221262685Sdelphij><P
8222262685Sdelphij><SPAN
8223262685SdelphijCLASS="emphasis"
8224262685Sdelphij><I
8225262685SdelphijCLASS="EMPHASIS"
8226262685Sdelphij>REQ_NEXT_CHOICE</I
8227262685Sdelphij></SPAN
8228262685Sdelphij> 
8229262685Sdelphij    Place the successor value of the current value in the buffer. 
8230262685Sdelphij    </P
8231262685Sdelphij></LI
8232262685Sdelphij><LI
8233262685Sdelphij><P
8234262685Sdelphij><SPAN
8235262685SdelphijCLASS="emphasis"
8236262685Sdelphij><I
8237262685SdelphijCLASS="EMPHASIS"
8238262685Sdelphij>REQ_PREV_CHOICE</I
8239262685Sdelphij></SPAN
8240262685Sdelphij> 
8241262685Sdelphij    Place the predecessor value of the current value in the buffer.
8242262685Sdelphij    </P
8243262685Sdelphij></LI
8244262685Sdelphij></UL
8245262685Sdelphij><P
8246262685Sdelphij>Of the built-in field types, only TYPE_ENUM has built-in successor and
8247262685Sdelphijpredecessor functions. When you define a field type of your own (see Custom
8248262685SdelphijValidation Types), you can associate our own ordering functions.</P
8249262685Sdelphij></DIV
8250262685Sdelphij><DIV
8251262685SdelphijCLASS="SECT3"
8252262685Sdelphij><HR><H4
8253262685SdelphijCLASS="SECT3"
8254262685Sdelphij><A
8255262685SdelphijNAME="APPLICCOMMANDS"
8256262685Sdelphij>18.6.7. Application Commands</A
8257262685Sdelphij></H4
8258262685Sdelphij><P
8259262685Sdelphij>Form requests are represented as integers above the curses value greater than
8260262685SdelphijKEY_MAX and less than or equal to the constant MAX_COMMAND.  A value within this
8261262685Sdelphijrange gets ignored by form_driver(). So this can be used for any purpose by the
8262262685Sdelphijapplication. It can be treated as an application specific action and take
8263262685Sdelphijcorresponding action.</P
8264262685Sdelphij></DIV
8265262685Sdelphij></DIV
8266262685Sdelphij></DIV
8267262685Sdelphij><DIV
8268262685SdelphijCLASS="SECT1"
8269262685Sdelphij><HR><H2
8270262685SdelphijCLASS="SECT1"
8271262685Sdelphij><A
8272262685SdelphijNAME="TOOLS"
8273262685Sdelphij>19. Tools and Widget Libraries</A
8274262685Sdelphij></H2
8275262685Sdelphij><P
8276262685Sdelphij> 
8277262685SdelphijNow that you have seen the capabilities of ncurses and its sister libraries, you
8278262685Sdelphijare rolling your sleeves up and gearing for a project that heavily manipulates
8279262685Sdelphijscreen. But wait..  It can be pretty difficult to write and maintain complex GUI
8280262685Sdelphijwidgets in plain ncurses or even with the additional libraries. There are some
8281262685Sdelphijready-to-use tools and widget libraries that can be used instead of writing your
8282262685Sdelphijown widgets. You can use some of them, get ideas from the code, or even extend
8283262685Sdelphijthem.</P
8284262685Sdelphij><DIV
8285262685SdelphijCLASS="SECT2"
8286262685Sdelphij><HR><H3
8287262685SdelphijCLASS="SECT2"
8288262685Sdelphij><A
8289262685SdelphijNAME="CDK"
8290262685Sdelphij>19.1. CDK (Curses Development Kit)</A
8291262685Sdelphij></H3
8292262685Sdelphij><P
8293262685Sdelphij>In the author's words </P
8294262685Sdelphij><P
8295262685Sdelphij><SPAN
8296262685SdelphijCLASS="emphasis"
8297262685Sdelphij><I
8298262685SdelphijCLASS="EMPHASIS"
8299262685Sdelphij> 
8300262685SdelphijCDK stands for 'Curses Development Kit' and it currently contains 21 ready
8301262685Sdelphijto use widgets which facilitate the speedy development of full screen
8302262685Sdelphijcurses programs. </I
8303262685Sdelphij></SPAN
8304262685Sdelphij></P
8305262685Sdelphij><P
8306262685Sdelphij>The kit provides some useful widgets, which can be used in your programs
8307262685Sdelphijdirectly. It's pretty well written and the documentation is very good. The
8308262685Sdelphijexamples in the examples directory can be a good place to start for beginners.
8309262685SdelphijThe CDK can be downloaded from <A
8310262685SdelphijHREF="http://invisible-island.net/cdk/"
8311262685SdelphijTARGET="_top"
8312262685Sdelphij>http://invisible-island.net/cdk/</A
8313262685Sdelphij>
8314262685Sdelphij. Follow the instructions in 
8315262685SdelphijREADME file to install it.</P
8316262685Sdelphij><DIV
8317262685SdelphijCLASS="SECT3"
8318262685Sdelphij><HR><H4
8319262685SdelphijCLASS="SECT3"
8320262685Sdelphij><A
8321262685SdelphijNAME="WIDGETLIST"
8322262685Sdelphij>19.1.1. Widget List</A
8323262685Sdelphij></H4
8324262685Sdelphij><P
8325262685Sdelphij>The following is the list of widgets provided with cdk and their description.</P
8326262685Sdelphij><PRE
8327262685SdelphijCLASS="PROGRAMLISTING"
8328262685Sdelphij>Widget Type           Quick Description
8329166124Srafan===========================================================================
8330166124SrafanAlphalist             Allows a user to select from a list of words, with
8331166124Srafan                      the ability to narrow the search list by typing in a
8332166124Srafan                      few characters of the desired word.
8333166124SrafanButtonbox             This creates a multiple button widget. 
8334166124SrafanCalendar              Creates a little simple calendar widget.
8335166124SrafanDialog                Prompts the user with a message, and the user
8336166124Srafan                      can pick an answer from the buttons provided.
8337166124SrafanEntry                 Allows the user to enter various types of information.
8338166124SrafanFile Selector         A file selector built from Cdk base widgets. This
8339166124Srafan                      example shows how to create more complicated widgets
8340166124Srafan                      using the Cdk widget library.
8341166124SrafanGraph                 Draws a graph.
8342166124SrafanHistogram             Draws a histogram.
8343166124SrafanItem List             Creates a pop up field which allows the user to select
8344166124Srafan                      one of several choices in a small field. Very useful
8345166124Srafan                      for things like days of the week or month names.
8346166124SrafanLabel                 Displays messages in a pop up box, or the label can be
8347166124Srafan                      considered part of the screen.
8348166124SrafanMarquee               Displays a message in a scrolling marquee.
8349166124SrafanMatrix                Creates a complex matrix with lots of options.
8350166124SrafanMenu                  Creates a pull-down menu interface.
8351166124SrafanMultiple Line Entry   A multiple line entry field. Very useful
8352166124Srafan                      for long fields. (like a description
8353166124Srafan                      field)
8354166124SrafanRadio List            Creates a radio button list.
8355166124SrafanScale                 Creates a numeric scale. Used for allowing a user to
8356166124Srafan                      pick a numeric value and restrict them to a range of 
8357166124Srafan                      values.
8358166124SrafanScrolling List        Creates a scrolling list/menu list.
8359166124SrafanScrolling Window      Creates a scrolling log file viewer. Can add 
8360166124Srafan                      information into the window while its running. 
8361166124Srafan                      A good widget for displaying the progress of
8362166124Srafan                      something. (akin to a console window)
8363166124SrafanSelection List        Creates a multiple option selection list.
8364166124SrafanSlider                Akin to the scale widget, this widget provides a
8365166124Srafan                      visual slide bar to represent the numeric value.
8366166124SrafanTemplate              Creates a entry field with character sensitive 
8367166124Srafan                      positions. Used for pre-formatted fields like
8368166124Srafan                      dates and phone numbers.
8369166124SrafanViewer                This is a file/information viewer. Very useful
8370166124Srafan                      when you need to display loads of information.
8371262685Sdelphij===========================================================================</PRE
8372262685Sdelphij><P
8373262685Sdelphij>A few of the widgets are modified by Thomas Dickey in recent versions.</P
8374262685Sdelphij></DIV
8375262685Sdelphij><DIV
8376262685SdelphijCLASS="SECT3"
8377262685Sdelphij><HR><H4
8378262685SdelphijCLASS="SECT3"
8379262685Sdelphij><A
8380262685SdelphijNAME="CDKATTRACT"
8381262685Sdelphij>19.1.2. Some Attractive Features</A
8382262685Sdelphij></H4
8383262685Sdelphij><P
8384262685Sdelphij>Apart from making our life easier with readily usable widgets, cdk solves one
8385262685Sdelphijfrustrating problem with printing multi colored strings, justified strings
8386262685Sdelphijelegantly.  Special formatting tags can be embedded in the strings which are
8387262685Sdelphijpassed to CDK functions. For Example</P
8388262685Sdelphij><P
8389262685Sdelphij>If the string</P
8390262685Sdelphij><PRE
8391262685SdelphijCLASS="PROGRAMLISTING"
8392262685Sdelphij>"&lt;/B/1&gt;This line should have a yellow foreground and a blue
8393262685Sdelphijbackground.&lt;!1&gt;"</PRE
8394262685Sdelphij><P
8395262685Sdelphij>given as a parameter to newCDKLabel(), it prints the line with yellow foreground
8396262685Sdelphijand blue background. There are other tags available for justifying string,
8397262685Sdelphijembedding special drawing characters etc.. Please refer to the man page
8398262685Sdelphijcdk_display(3X) for details. The man page explains the usage with nice examples.</P
8399262685Sdelphij></DIV
8400262685Sdelphij><DIV
8401262685SdelphijCLASS="SECT3"
8402262685Sdelphij><HR><H4
8403262685SdelphijCLASS="SECT3"
8404262685Sdelphij><A
8405262685SdelphijNAME="CDKCONCLUSION"
8406262685Sdelphij>19.1.3. Conclusion</A
8407262685Sdelphij></H4
8408262685Sdelphij><P
8409262685Sdelphij>All in all, CDK is a well-written package of widgets, which if used properly can
8410262685Sdelphijform a strong frame work for developing complex GUI.</P
8411262685Sdelphij></DIV
8412262685Sdelphij></DIV
8413262685Sdelphij><DIV
8414262685SdelphijCLASS="SECT2"
8415262685Sdelphij><HR><H3
8416262685SdelphijCLASS="SECT2"
8417262685Sdelphij><A
8418262685SdelphijNAME="DIALOG"
8419262685Sdelphij>19.2. The dialog</A
8420262685Sdelphij></H3
8421262685Sdelphij><P
8422262685Sdelphij>Long long ago, in September 1994, when few people knew linux, Jeff Tranter wrote
8423262685Sdelphijan <A
8424262685SdelphijHREF="http://www2.linuxjournal.com/lj-issues/issue5/2807.html"
8425262685SdelphijTARGET="_top"
8426262685Sdelphij>article</A
8427262685Sdelphij> on dialog in Linux Journal. He starts the article with these words..</P
8428262685Sdelphij><P
8429262685Sdelphij><SPAN
8430262685SdelphijCLASS="emphasis"
8431262685Sdelphij><I
8432262685SdelphijCLASS="EMPHASIS"
8433262685Sdelphij>Linux is based on the Unix operating system, but also features a number of
8434262685Sdelphijunique and useful kernel features and application programs that often go beyond
8435262685Sdelphijwhat is available under Unix. One little-known gem is "dialog", a utility for
8436262685Sdelphijcreating professional-looking dialog boxes from within shell scripts. This
8437262685Sdelphijarticle presents a tutorial introduction to the dialog utility, and shows
8438262685Sdelphijexamples of how and where it can be used</I
8439262685Sdelphij></SPAN
8440262685Sdelphij></P
8441262685Sdelphij><P
8442262685Sdelphij> 
8443262685SdelphijAs he explains, dialog is a real gem in making professional-looking dialog boxes
8444262685Sdelphijwith ease. It creates a variety of dialog boxes, menus, check lists etc.. It is
8445262685Sdelphijusually installed by default. If not, you can download it from <A
8446262685SdelphijHREF="http://invisible-island.net/dialog/"
8447262685SdelphijTARGET="_top"
8448262685Sdelphij>Thomas Dickey</A
8449262685Sdelphij>'s site. </P
8450262685Sdelphij><P
8451262685Sdelphij>The above-mentioned article gives a very good overview of its uses and
8452262685Sdelphijcapabilites.  The man page has more details. It can be used in variety of
8453262685Sdelphijsituations. One good example is building of linux kernel in text mode. Linux
8454262685Sdelphijkernel uses a modified version of dialog tailored for its needs. </P
8455262685Sdelphij><P
8456262685Sdelphij>dialog was initially designed to be used with shell scripts. If you want to use
8457262685Sdelphijits functionality in a c program, then you can use libdialog. The documentation
8458262685Sdelphijregarding this is sparse. Definitive reference is the dialog.h header file which
8459262685Sdelphijcomes with the library. You may need to hack here and there to get the required
8460262685Sdelphijoutput. The source is easily customizable. I have used it on a number of
8461262685Sdelphijoccasions by modifying the code.</P
8462262685Sdelphij></DIV
8463262685Sdelphij><DIV
8464262685SdelphijCLASS="SECT2"
8465262685Sdelphij><HR><H3
8466262685SdelphijCLASS="SECT2"
8467262685Sdelphij><A
8468262685SdelphijNAME="PERLCURSES"
8469262685Sdelphij>19.3. Perl Curses Modules CURSES::FORM and CURSES::WIDGETS</A
8470262685Sdelphij></H3
8471262685Sdelphij><P
8472262685Sdelphij>The perl module Curses, Curses::Form and Curses::Widgets give access to curses
8473262685Sdelphijfrom perl.  If you have curses and basic perl is installed, you can get these
8474262685Sdelphijmodules from <A
8475262685SdelphijHREF="http://www.cpan.org/modules/01modules.index.html"
8476262685SdelphijTARGET="_top"
8477262685Sdelphij> CPAN
8478262685SdelphijAll Modules page</A
8479262685Sdelphij>.  Get the three zipped modules in the Curses category.
8480262685SdelphijOnce installed you can use these modules from perl scripts like any other
8481262685Sdelphijmodule. For more information on perl modules see perlmod man page. The above
8482262685Sdelphijmodules come with good documentation and they have some demo scripts to test the
8483262685Sdelphijfunctionality. Though the widgets provided are very rudimentary, these modules
8484262685Sdelphijprovide good access to curses library from perl.</P
8485262685Sdelphij><P
8486262685Sdelphij>Some of my code examples are converted to perl by Anuradha Ratnaweera and they
8487262685Sdelphijare available in the <TT
8488262685SdelphijCLASS="LITERAL"
8489262685Sdelphij>perl</TT
8490262685Sdelphij> directory.</P
8491262685Sdelphij><P
8492262685Sdelphij> 
8493262685SdelphijFor more information see man pages Curses(3) , Curses::Form(3) and
8494262685SdelphijCurses::Widgets(3).  These pages are installed only when the above modules are
8495262685Sdelphijacquired and installed.</P
8496262685Sdelphij></DIV
8497262685Sdelphij></DIV
8498262685Sdelphij><DIV
8499262685SdelphijCLASS="SECT1"
8500262685Sdelphij><HR><H2
8501262685SdelphijCLASS="SECT1"
8502262685Sdelphij><A
8503262685SdelphijNAME="JUSTFORFUN"
8504262685Sdelphij>20. Just For Fun !!!</A
8505262685Sdelphij></H2
8506262685Sdelphij><P
8507262685Sdelphij>This section contains few programs written by me just for fun. They don't
8508262685Sdelphijsignify a better programming practice or the best way of using ncurses. They are
8509262685Sdelphijprovided here so as to allow beginners to get ideas and add more programs to
8510262685Sdelphijthis section.  If you have written a couple of nice, simple programs in curses
8511262685Sdelphijand want them to included here, contact <A
8512262685SdelphijHREF="mailto:ppadala@gmail.com"
8513262685SdelphijTARGET="_top"
8514262685Sdelphij>me</A
8515262685Sdelphij>.</P
8516262685Sdelphij><DIV
8517262685SdelphijCLASS="SECT2"
8518262685Sdelphij><HR><H3
8519262685SdelphijCLASS="SECT2"
8520262685Sdelphij><A
8521262685SdelphijNAME="GAMEOFLIFE"
8522262685Sdelphij>20.1. The Game of Life</A
8523262685Sdelphij></H3
8524262685Sdelphij><P
8525262685Sdelphij>Game of life is a wonder of math. In 
8526262685Sdelphij<A
8527262685SdelphijHREF="http://www.math.com/students/wonders/life/life.html"
8528262685SdelphijTARGET="_top"
8529262685Sdelphij>Paul Callahan</A
8530262685Sdelphij>'s words</P
8531262685Sdelphij><PRE
8532262685SdelphijCLASS="PROGRAMLISTING"
8533262685Sdelphij><SPAN
8534262685SdelphijCLASS="emphasis"
8535262685Sdelphij><I
8536262685SdelphijCLASS="EMPHASIS"
8537262685Sdelphij>The Game of Life (or simply Life) is not a game in the conventional sense. There
8538166124Srafanare no players, and no winning or losing. Once the "pieces" are placed in the
8539166124Srafanstarting position, the rules determine everything that happens later.
8540166124SrafanNevertheless, Life is full of surprises! In most cases, it is impossible to look
8541166124Srafanat a starting position (or pattern) and see what will happen in the future. The
8542262685Sdelphijonly way to find out is to follow the rules of the game.</I
8543262685Sdelphij></SPAN
8544262685Sdelphij></PRE
8545262685Sdelphij><P
8546262685Sdelphij>This program starts with a simple inverted U pattern and shows how wonderful
8547262685Sdelphijlife works. There is a lot of room for improvement in the program. You can let
8548262685Sdelphijthe user enter pattern of his choice or even take input from a file. You can
8549262685Sdelphijalso change rules and play with a lot of variations. Search on <A
8550262685SdelphijHREF="http://www.google.com"
8551262685SdelphijTARGET="_top"
8552262685Sdelphij>google</A
8553262685Sdelphij> for interesting information on game
8554262685Sdelphijof life.</P
8555262685Sdelphij><P
8556262685Sdelphij><SPAN
8557262685SdelphijCLASS="emphasis"
8558262685Sdelphij><I
8559262685SdelphijCLASS="EMPHASIS"
8560262685Sdelphij>File Path: JustForFun/life.c</I
8561262685Sdelphij></SPAN
8562262685Sdelphij></P
8563262685Sdelphij></DIV
8564262685Sdelphij><DIV
8565262685SdelphijCLASS="SECT2"
8566262685Sdelphij><HR><H3
8567262685SdelphijCLASS="SECT2"
8568262685Sdelphij><A
8569262685SdelphijNAME="MAGIC"
8570262685Sdelphij>20.2. Magic Square</A
8571262685Sdelphij></H3
8572262685Sdelphij><P
8573262685Sdelphij>Magic Square, another wonder of math, is very simple to understand but very
8574262685Sdelphijdifficult to make. In a magic square sum of the numbers in each row, each column
8575262685Sdelphijis equal.  Even diagnol sum can be equal. There are many variations which have
8576262685Sdelphijspecial properties.</P
8577262685Sdelphij><P
8578262685Sdelphij>This program creates a simple magic square of odd order.</P
8579262685Sdelphij><P
8580262685Sdelphij><SPAN
8581262685SdelphijCLASS="emphasis"
8582262685Sdelphij><I
8583262685SdelphijCLASS="EMPHASIS"
8584262685Sdelphij>File Path: JustForFun/magic.c</I
8585262685Sdelphij></SPAN
8586262685Sdelphij></P
8587262685Sdelphij></DIV
8588262685Sdelphij><DIV
8589262685SdelphijCLASS="SECT2"
8590262685Sdelphij><HR><H3
8591262685SdelphijCLASS="SECT2"
8592262685Sdelphij><A
8593262685SdelphijNAME="HANOI"
8594262685Sdelphij>20.3. Towers of Hanoi</A
8595262685Sdelphij></H3
8596262685Sdelphij><P
8597262685Sdelphij>The famous towers of hanoi solver. The aim of the game is to move the disks on
8598262685Sdelphijthe first peg to last peg, using middle peg as a temporary stay. The catch is
8599262685Sdelphijnot to place a larger disk over a small disk at any time.</P
8600262685Sdelphij><P
8601262685Sdelphij><SPAN
8602262685SdelphijCLASS="emphasis"
8603262685Sdelphij><I
8604262685SdelphijCLASS="EMPHASIS"
8605262685Sdelphij>File Path: JustForFun/hanoi.c</I
8606262685Sdelphij></SPAN
8607262685Sdelphij></P
8608262685Sdelphij></DIV
8609262685Sdelphij><DIV
8610262685SdelphijCLASS="SECT2"
8611262685Sdelphij><HR><H3
8612262685SdelphijCLASS="SECT2"
8613262685Sdelphij><A
8614262685SdelphijNAME="QUEENS"
8615262685Sdelphij>20.4. Queens Puzzle</A
8616262685Sdelphij></H3
8617262685Sdelphij><P
8618262685Sdelphij>The objective of the famous N-Queen puzzle is to put N queens on a N X N chess
8619262685Sdelphijboard without attacking each other. </P
8620262685Sdelphij><P
8621262685Sdelphij>This program solves it with a simple backtracking technique.</P
8622262685Sdelphij><P
8623262685Sdelphij><SPAN
8624262685SdelphijCLASS="emphasis"
8625262685Sdelphij><I
8626262685SdelphijCLASS="EMPHASIS"
8627262685Sdelphij>File Path: JustForFun/queens.c</I
8628262685Sdelphij></SPAN
8629262685Sdelphij></P
8630262685Sdelphij></DIV
8631262685Sdelphij><DIV
8632262685SdelphijCLASS="SECT2"
8633262685Sdelphij><HR><H3
8634262685SdelphijCLASS="SECT2"
8635262685Sdelphij><A
8636262685SdelphijNAME="SHUFFLE"
8637262685Sdelphij>20.5. Shuffle</A
8638262685Sdelphij></H3
8639262685Sdelphij><P
8640262685Sdelphij>A fun game, if you have time to kill. </P
8641262685Sdelphij><P
8642262685Sdelphij><SPAN
8643262685SdelphijCLASS="emphasis"
8644262685Sdelphij><I
8645262685SdelphijCLASS="EMPHASIS"
8646262685Sdelphij>File Path: JustForFun/shuffle.c</I
8647262685Sdelphij></SPAN
8648262685Sdelphij></P
8649262685Sdelphij></DIV
8650262685Sdelphij><DIV
8651262685SdelphijCLASS="SECT2"
8652262685Sdelphij><HR><H3
8653262685SdelphijCLASS="SECT2"
8654262685Sdelphij><A
8655262685SdelphijNAME="TT"
8656262685Sdelphij>20.6. Typing Tutor</A
8657262685Sdelphij></H3
8658262685Sdelphij><P
8659262685Sdelphij>A simple typing tutor, I created more out of need than for ease of use. If you
8660262685Sdelphijknow how to put your fingers correctly on the keyboard, but lack practice, this
8661262685Sdelphijcan be helpful. </P
8662262685Sdelphij><P
8663262685Sdelphij><SPAN
8664262685SdelphijCLASS="emphasis"
8665262685Sdelphij><I
8666262685SdelphijCLASS="EMPHASIS"
8667262685Sdelphij>File Path: JustForFun/tt.c</I
8668262685Sdelphij></SPAN
8669262685Sdelphij></P
8670262685Sdelphij></DIV
8671262685Sdelphij></DIV
8672262685Sdelphij><DIV
8673262685SdelphijCLASS="SECT1"
8674262685Sdelphij><HR><H2
8675262685SdelphijCLASS="SECT1"
8676262685Sdelphij><A
8677262685SdelphijNAME="REF"
8678262685Sdelphij>21. References</A
8679262685Sdelphij></H2
8680262685Sdelphij><P
8681262685Sdelphij></P
8682262685Sdelphij><UL
8683262685Sdelphij><LI
8684262685Sdelphij><P
8685262685Sdelphij>NCURSES man pages </P
8686262685Sdelphij></LI
8687262685Sdelphij><LI
8688262685Sdelphij><P
8689262685Sdelphij>NCURSES FAQ at <A
8690262685SdelphijHREF="http://invisible-island.net/ncurses/ncurses.faq.html"
8691262685SdelphijTARGET="_top"
8692262685Sdelphij>http://invisible-island.net/ncurses/ncurses.faq.html</A
8693262685Sdelphij>
8694262685Sdelphij    </P
8695262685Sdelphij></LI
8696262685Sdelphij><LI
8697262685Sdelphij><P
8698262685Sdelphij>Writing programs with NCURSES by Eric Raymond and Zeyd M.
8699262685SdelphijBen-Halim at 
8700262685Sdelphij<A
8701262685SdelphijHREF="http://invisible-island.net/ncurses/ncurses-intro.html"
8702262685SdelphijTARGET="_top"
8703262685Sdelphij>http://invisible-island.net/ncurses/ncurses-intro.html</A
8704262685Sdelphij> - somewhat
8705262685Sdelphijobsolete. I was inspired by this document and the structure of this HOWTO
8706262685Sdelphijfollows from the original document</P
8707262685Sdelphij></LI
8708262685Sdelphij></UL
8709262685Sdelphij></DIV
8710262685Sdelphij></DIV
8711262685Sdelphij></BODY
8712262685Sdelphij></HTML
8713262685Sdelphij>