1 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
---|
2 | <html>
|
---|
3 | <head>
|
---|
4 | <meta name="generator" content=
|
---|
5 | "HTML Tidy for Linux/x86 (vers 1st December 2004), see www.w3.org">
|
---|
6 | <title>NCURSES Programming HOWTO</title>
|
---|
7 | <meta name="GENERATOR" content=
|
---|
8 | "Modular DocBook HTML Stylesheet Version 1.7">
|
---|
9 | </head>
|
---|
10 | <body class="ARTICLE" bgcolor="#FFFFFF" text="#000000" link=
|
---|
11 | "#0000FF" vlink="#840084" alink="#0000FF">
|
---|
12 | <div class="ARTICLE">
|
---|
13 | <div class="TITLEPAGE">
|
---|
14 | <h1 class="TITLE"><a name="AEN2" id="AEN2">NCURSES Programming
|
---|
15 | HOWTO</a></h1>
|
---|
16 | <h3 class="AUTHOR"><a name="AEN4" id="AEN4">Pradeep Padala</a></h3>
|
---|
17 | <div class="AFFILIATION">
|
---|
18 | <div class="ADDRESS">
|
---|
19 | <p class="ADDRESS"><code class="EMAIL"><<a href=
|
---|
20 | "mailto:ppadala@gmail.com">ppadala@gmail.com</a>></code></p>
|
---|
21 | </div>
|
---|
22 | </div>
|
---|
23 | <p class="PUBDATE">v1.9, 2005-06-20<br></p>
|
---|
24 | <div class="REVHISTORY">
|
---|
25 | <table width="100%" border="0">
|
---|
26 | <tr>
|
---|
27 | <th align="left" valign="top" colspan="3"><b>Revision
|
---|
28 | History</b></th>
|
---|
29 | </tr>
|
---|
30 | <tr>
|
---|
31 | <td align="left">Revision 1.9</td>
|
---|
32 | <td align="left">2005-06-20</td>
|
---|
33 | <td align="left">Revised by: ppadala</td>
|
---|
34 | </tr>
|
---|
35 | <tr>
|
---|
36 | <td align="left" colspan="3">The license has been changed to the
|
---|
37 | MIT-style license used by NCURSES. Note that the programs are also
|
---|
38 | re-licensed under this.</td>
|
---|
39 | </tr>
|
---|
40 | <tr>
|
---|
41 | <td align="left">Revision 1.8</td>
|
---|
42 | <td align="left">2005-06-17</td>
|
---|
43 | <td align="left">Revised by: ppadala</td>
|
---|
44 | </tr>
|
---|
45 | <tr>
|
---|
46 | <td align="left" colspan="3">Lots of updates. Added references and
|
---|
47 | perl examples. Changes to examples. Many grammatical and stylistic
|
---|
48 | changes to the content. Changes to NCURSES history.</td>
|
---|
49 | </tr>
|
---|
50 | <tr>
|
---|
51 | <td align="left">Revision 1.7.1</td>
|
---|
52 | <td align="left">2002-06-25</td>
|
---|
53 | <td align="left">Revised by: ppadala</td>
|
---|
54 | </tr>
|
---|
55 | <tr>
|
---|
56 | <td align="left" colspan="3">Added a README file for building and
|
---|
57 | instructions for building from source.</td>
|
---|
58 | </tr>
|
---|
59 | <tr>
|
---|
60 | <td align="left">Revision 1.7</td>
|
---|
61 | <td align="left">2002-06-25</td>
|
---|
62 | <td align="left">Revised by: ppadala</td>
|
---|
63 | </tr>
|
---|
64 | <tr>
|
---|
65 | <td align="left" colspan="3">Added "Other formats" section and made
|
---|
66 | a lot of fancy changes to the programs. Inlining of programs is
|
---|
67 | gone.</td>
|
---|
68 | </tr>
|
---|
69 | <tr>
|
---|
70 | <td align="left">Revision 1.6.1</td>
|
---|
71 | <td align="left">2002-02-24</td>
|
---|
72 | <td align="left">Revised by: ppadala</td>
|
---|
73 | </tr>
|
---|
74 | <tr>
|
---|
75 | <td align="left" colspan="3">Removed the old Changelog section,
|
---|
76 | cleaned the makefiles</td>
|
---|
77 | </tr>
|
---|
78 | <tr>
|
---|
79 | <td align="left">Revision 1.6</td>
|
---|
80 | <td align="left">2002-02-16</td>
|
---|
81 | <td align="left">Revised by: ppadala</td>
|
---|
82 | </tr>
|
---|
83 | <tr>
|
---|
84 | <td align="left" colspan="3">Corrected a lot of spelling mistakes,
|
---|
85 | added ACS variables section</td>
|
---|
86 | </tr>
|
---|
87 | <tr>
|
---|
88 | <td align="left">Revision 1.5</td>
|
---|
89 | <td align="left">2002-01-05</td>
|
---|
90 | <td align="left">Revised by: ppadala</td>
|
---|
91 | </tr>
|
---|
92 | <tr>
|
---|
93 | <td align="left" colspan="3">Changed structure to present proper
|
---|
94 | TOC</td>
|
---|
95 | </tr>
|
---|
96 | <tr>
|
---|
97 | <td align="left">Revision 1.3.1</td>
|
---|
98 | <td align="left">2001-07-26</td>
|
---|
99 | <td align="left">Revised by: ppadala</td>
|
---|
100 | </tr>
|
---|
101 | <tr>
|
---|
102 | <td align="left" colspan="3">Corrected maintainers paragraph,
|
---|
103 | Corrected stable release number</td>
|
---|
104 | </tr>
|
---|
105 | <tr>
|
---|
106 | <td align="left">Revision 1.3</td>
|
---|
107 | <td align="left">2001-07-24</td>
|
---|
108 | <td align="left">Revised by: ppadala</td>
|
---|
109 | </tr>
|
---|
110 | <tr>
|
---|
111 | <td align="left" colspan="3">Added copyright notices to main
|
---|
112 | document (LDP license) and programs (GPL), Corrected
|
---|
113 | printw_example.</td>
|
---|
114 | </tr>
|
---|
115 | <tr>
|
---|
116 | <td align="left">Revision 1.2</td>
|
---|
117 | <td align="left">2001-06-05</td>
|
---|
118 | <td align="left">Revised by: ppadala</td>
|
---|
119 | </tr>
|
---|
120 | <tr>
|
---|
121 | <td align="left" colspan="3">Incorporated ravi's changes. Mainly to
|
---|
122 | introduction, menu, form, justforfun sections</td>
|
---|
123 | </tr>
|
---|
124 | <tr>
|
---|
125 | <td align="left">Revision 1.1</td>
|
---|
126 | <td align="left">2001-05-22</td>
|
---|
127 | <td align="left">Revised by: ppadala</td>
|
---|
128 | </tr>
|
---|
129 | <tr>
|
---|
130 | <td align="left" colspan="3">Added "a word about window" section,
|
---|
131 | Added scanw_example.</td>
|
---|
132 | </tr>
|
---|
133 | </table>
|
---|
134 | </div>
|
---|
135 | <div>
|
---|
136 | <div class="ABSTRACT"><a name="AEN67" id="AEN67"></a>
|
---|
137 | <p><em>This document is intended to be an "All in One" guide for
|
---|
138 | programming with ncurses and its sister libraries. We graduate from
|
---|
139 | a simple "Hello World" program to more complex form manipulation.
|
---|
140 | No prior experience in ncurses is assumed. Send comments to
|
---|
141 | <a href="mailto:ppadala@gmail.com" target="_top">this
|
---|
142 | address</a></em></p>
|
---|
143 | </div>
|
---|
144 | </div>
|
---|
145 | <hr></div>
|
---|
146 | <div class="TOC">
|
---|
147 | <dl>
|
---|
148 | <dt><b>Table of Contents</b></dt>
|
---|
149 | <dt>1. <a href="#INTRO">Introduction</a></dt>
|
---|
150 | <dd>
|
---|
151 | <dl>
|
---|
152 | <dt>1.1. <a href="#WHATIS">What is NCURSES?</a></dt>
|
---|
153 | <dt>1.2. <a href="#WHATCANWEDO">What we can do with
|
---|
154 | NCURSES</a></dt>
|
---|
155 | <dt>1.3. <a href="#WHERETOGETIT">Where to get it</a></dt>
|
---|
156 | <dt>1.4. <a href="#PURPOSE">Purpose/Scope of the document</a></dt>
|
---|
157 | <dt>1.5. <a href="#ABOUTPROGRAMS">About the Programs</a></dt>
|
---|
158 | <dt>1.6. <a href="#OTHERFORMATS">Other Formats of the
|
---|
159 | document</a></dt>
|
---|
160 | <dt>1.7. <a href="#CREDITS">Credits</a></dt>
|
---|
161 | <dt>1.8. <a href="#WISHLIST">Wish List</a></dt>
|
---|
162 | <dt>1.9. <a href="#COPYRIGHT">Copyright</a></dt>
|
---|
163 | </dl>
|
---|
164 | </dd>
|
---|
165 | <dt>2. <a href="#HELLOWORLD">Hello World !!!</a></dt>
|
---|
166 | <dd>
|
---|
167 | <dl>
|
---|
168 | <dt>2.1. <a href="#COMPILECURSES">Compiling With the NCURSES
|
---|
169 | Library</a></dt>
|
---|
170 | <dt>2.2. <a href="#DISSECTION">Dissection</a></dt>
|
---|
171 | </dl>
|
---|
172 | </dd>
|
---|
173 | <dt>3. <a href="#GORY">The Gory Details</a></dt>
|
---|
174 | <dt>4. <a href="#INIT">Initialization</a></dt>
|
---|
175 | <dd>
|
---|
176 | <dl>
|
---|
177 | <dt>4.1. <a href="#ABOUTINIT">Initialization functions</a></dt>
|
---|
178 | <dt>4.2. <a href="#RAWCBREAK">raw() and cbreak()</a></dt>
|
---|
179 | <dt>4.3. <a href="#ECHONOECHO">echo() and noecho()</a></dt>
|
---|
180 | <dt>4.4. <a href="#KEYPAD">keypad()</a></dt>
|
---|
181 | <dt>4.5. <a href="#HALFDELAY">halfdelay()</a></dt>
|
---|
182 | <dt>4.6. <a href="#MISCINIT">Miscellaneous Initialization
|
---|
183 | functions</a></dt>
|
---|
184 | <dt>4.7. <a href="#INITEX">An Example</a></dt>
|
---|
185 | </dl>
|
---|
186 | </dd>
|
---|
187 | <dt>5. <a href="#AWORDWINDOWS">A Word about Windows</a></dt>
|
---|
188 | <dt>6. <a href="#PRINTW">Output functions</a></dt>
|
---|
189 | <dd>
|
---|
190 | <dl>
|
---|
191 | <dt>6.1. <a href="#ADDCHCLASS">addch() class of functions</a></dt>
|
---|
192 | <dt>6.2. <a href="#AEN298">mvaddch(), waddch() and
|
---|
193 | mvwaddch()</a></dt>
|
---|
194 | <dt>6.3. <a href="#PRINTWCLASS">printw() class of
|
---|
195 | functions</a></dt>
|
---|
196 | <dt>6.4. <a href="#ADDSTRCLASS">addstr() class of
|
---|
197 | functions</a></dt>
|
---|
198 | <dt>6.5. <a href="#ACAUTION">A word of caution</a></dt>
|
---|
199 | </dl>
|
---|
200 | </dd>
|
---|
201 | <dt>7. <a href="#SCANW">Input functions</a></dt>
|
---|
202 | <dd>
|
---|
203 | <dl>
|
---|
204 | <dt>7.1. <a href="#GETCHCLASS">getch() class of functions</a></dt>
|
---|
205 | <dt>7.2. <a href="#SCANWCLASS">scanw() class of functions</a></dt>
|
---|
206 | <dt>7.3. <a href="#GETSTRCLASS">getstr() class of
|
---|
207 | functions</a></dt>
|
---|
208 | <dt>7.4. <a href="#GETSTREX">Some examples</a></dt>
|
---|
209 | </dl>
|
---|
210 | </dd>
|
---|
211 | <dt>8. <a href="#ATTRIB">Attributes</a></dt>
|
---|
212 | <dd>
|
---|
213 | <dl>
|
---|
214 | <dt>8.1. <a href="#ATTRIBDETAILS">The details</a></dt>
|
---|
215 | <dt>8.2. <a href="#ATTRONVSATTRSET">attron() vs attrset()</a></dt>
|
---|
216 | <dt>8.3. <a href="#ATTR_GET">attr_get()</a></dt>
|
---|
217 | <dt>8.4. <a href="#ATTR_FUNCS">attr_ functions</a></dt>
|
---|
218 | <dt>8.5. <a href="#WATTRFUNCS">wattr functions</a></dt>
|
---|
219 | <dt>8.6. <a href="#CHGAT">chgat() functions</a></dt>
|
---|
220 | </dl>
|
---|
221 | </dd>
|
---|
222 | <dt>9. <a href="#WINDOWS">Windows</a></dt>
|
---|
223 | <dd>
|
---|
224 | <dl>
|
---|
225 | <dt>9.1. <a href="#WINDOWBASICS">The basics</a></dt>
|
---|
226 | <dt>9.2. <a href="#LETBEWINDOW">Let there be a Window !!!</a></dt>
|
---|
227 | <dt>9.3. <a href="#BORDEREXEXPL">Explanation</a></dt>
|
---|
228 | <dt>9.4. <a href="#OTHERSTUFF">The other stuff in the
|
---|
229 | example</a></dt>
|
---|
230 | <dt>9.5. <a href="#OTHERBORDERFUNCS">Other Border
|
---|
231 | functions</a></dt>
|
---|
232 | </dl>
|
---|
233 | </dd>
|
---|
234 | <dt>10. <a href="#COLOR">Colors</a></dt>
|
---|
235 | <dd>
|
---|
236 | <dl>
|
---|
237 | <dt>10.1. <a href="#COLORBASICS">The basics</a></dt>
|
---|
238 | <dt>10.2. <a href="#CHANGECOLORDEFS">Changing Color
|
---|
239 | Definitions</a></dt>
|
---|
240 | <dt>10.3. <a href="#COLORCONTENT">Color Content</a></dt>
|
---|
241 | </dl>
|
---|
242 | </dd>
|
---|
243 | <dt>11. <a href="#KEYS">Interfacing with the key board</a></dt>
|
---|
244 | <dd>
|
---|
245 | <dl>
|
---|
246 | <dt>11.1. <a href="#KEYSBASICS">The Basics</a></dt>
|
---|
247 | <dt>11.2. <a href="#SIMPLEKEYEX">A Simple Key Usage
|
---|
248 | example</a></dt>
|
---|
249 | </dl>
|
---|
250 | </dd>
|
---|
251 | <dt>12. <a href="#MOUSE">Interfacing with the mouse</a></dt>
|
---|
252 | <dd>
|
---|
253 | <dl>
|
---|
254 | <dt>12.1. <a href="#MOUSEBASICS">The Basics</a></dt>
|
---|
255 | <dt>12.2. <a href="#GETTINGEVENTS">Getting the events</a></dt>
|
---|
256 | <dt>12.3. <a href="#MOUSETOGETHER">Putting it all Together</a></dt>
|
---|
257 | <dt>12.4. <a href="#MISCMOUSEFUNCS">Miscellaneous
|
---|
258 | Functions</a></dt>
|
---|
259 | </dl>
|
---|
260 | </dd>
|
---|
261 | <dt>13. <a href="#SCREEN">Screen Manipulation</a></dt>
|
---|
262 | <dd>
|
---|
263 | <dl>
|
---|
264 | <dt>13.1. <a href="#GETYX">getyx() functions</a></dt>
|
---|
265 | <dt>13.2. <a href="#SCREENDUMP">Screen Dumping</a></dt>
|
---|
266 | <dt>13.3. <a href="#WINDOWDUMP">Window Dumping</a></dt>
|
---|
267 | </dl>
|
---|
268 | </dd>
|
---|
269 | <dt>14. <a href="#MISC">Miscellaneous features</a></dt>
|
---|
270 | <dd>
|
---|
271 | <dl>
|
---|
272 | <dt>14.1. <a href="#CURSSET">curs_set()</a></dt>
|
---|
273 | <dt>14.2. <a href="#TEMPLEAVE">Temporarily Leaving Curses
|
---|
274 | mode</a></dt>
|
---|
275 | <dt>14.3. <a href="#ACSVARS">ACS_ variables</a></dt>
|
---|
276 | </dl>
|
---|
277 | </dd>
|
---|
278 | <dt>15. <a href="#OTHERLIB">Other libraries</a></dt>
|
---|
279 | <dt>16. <a href="#PANELS">Panel Library</a></dt>
|
---|
280 | <dd>
|
---|
281 | <dl>
|
---|
282 | <dt>16.1. <a href="#PANELBASICS">The Basics</a></dt>
|
---|
283 | <dt>16.2. <a href="#COMPILEPANELS">Compiling With the Panels
|
---|
284 | Library</a></dt>
|
---|
285 | <dt>16.3. <a href="#PANELBROWSING">Panel Window Browsing</a></dt>
|
---|
286 | <dt>16.4. <a href="#USERPTRUSING">Using User Pointers</a></dt>
|
---|
287 | <dt>16.5. <a href="#PANELMOVERESIZE">Moving and Resizing
|
---|
288 | Panels</a></dt>
|
---|
289 | <dt>16.6. <a href="#PANELSHOWHIDE">Hiding and Showing
|
---|
290 | Panels</a></dt>
|
---|
291 | <dt>16.7. <a href="#PANELABOVE">panel_above() and panel_below()
|
---|
292 | Functions</a></dt>
|
---|
293 | </dl>
|
---|
294 | </dd>
|
---|
295 | <dt>17. <a href="#MENUS">Menus Library</a></dt>
|
---|
296 | <dd>
|
---|
297 | <dl>
|
---|
298 | <dt>17.1. <a href="#MENUBASICS">The Basics</a></dt>
|
---|
299 | <dt>17.2. <a href="#COMPILEMENUS">Compiling With the Menu
|
---|
300 | Library</a></dt>
|
---|
301 | <dt>17.3. <a href="#MENUDRIVER">Menu Driver: The work horse of the
|
---|
302 | menu system</a></dt>
|
---|
303 | <dt>17.4. <a href="#MENUWINDOWS">Menu Windows</a></dt>
|
---|
304 | <dt>17.5. <a href="#SCROLLMENUS">Scrolling Menus</a></dt>
|
---|
305 | <dt>17.6. <a href="#MULTICOLUMN">Multi Columnar Menus</a></dt>
|
---|
306 | <dt>17.7. <a href="#MULTIVALUEMENUS">Multi Valued Menus</a></dt>
|
---|
307 | <dt>17.8. <a href="#MENUOPT">Menu Options</a></dt>
|
---|
308 | <dt>17.9. <a href="#MENUUSERPTR">The useful User Pointer</a></dt>
|
---|
309 | </dl>
|
---|
310 | </dd>
|
---|
311 | <dt>18. <a href="#FORMS">Forms Library</a></dt>
|
---|
312 | <dd>
|
---|
313 | <dl>
|
---|
314 | <dt>18.1. <a href="#FORMBASICS">The Basics</a></dt>
|
---|
315 | <dt>18.2. <a href="#COMPILEFORMS">Compiling With the Forms
|
---|
316 | Library</a></dt>
|
---|
317 | <dt>18.3. <a href="#PLAYFIELDS">Playing with Fields</a></dt>
|
---|
318 | <dt>18.4. <a href="#FORMWINDOWS">Form Windows</a></dt>
|
---|
319 | <dt>18.5. <a href="#FILEDVALIDATE">Field Validation</a></dt>
|
---|
320 | <dt>18.6. <a href="#FORMDRIVER">Form Driver: The work horse of the
|
---|
321 | forms system</a></dt>
|
---|
322 | </dl>
|
---|
323 | </dd>
|
---|
324 | <dt>19. <a href="#TOOLS">Tools and Widget Libraries</a></dt>
|
---|
325 | <dd>
|
---|
326 | <dl>
|
---|
327 | <dt>19.1. <a href="#CDK">CDK (Curses Development Kit)</a></dt>
|
---|
328 | <dt>19.2. <a href="#DIALOG">The dialog</a></dt>
|
---|
329 | <dt>19.3. <a href="#PERLCURSES">Perl Curses Modules CURSES::FORM
|
---|
330 | and CURSES::WIDGETS</a></dt>
|
---|
331 | </dl>
|
---|
332 | </dd>
|
---|
333 | <dt>20. <a href="#JUSTFORFUN">Just For Fun !!!</a></dt>
|
---|
334 | <dd>
|
---|
335 | <dl>
|
---|
336 | <dt>20.1. <a href="#GAMEOFLIFE">The Game of Life</a></dt>
|
---|
337 | <dt>20.2. <a href="#MAGIC">Magic Square</a></dt>
|
---|
338 | <dt>20.3. <a href="#HANOI">Towers of Hanoi</a></dt>
|
---|
339 | <dt>20.4. <a href="#QUEENS">Queens Puzzle</a></dt>
|
---|
340 | <dt>20.5. <a href="#SHUFFLE">Shuffle</a></dt>
|
---|
341 | <dt>20.6. <a href="#TT">Typing Tutor</a></dt>
|
---|
342 | </dl>
|
---|
343 | </dd>
|
---|
344 | <dt>21. <a href="#REF">References</a></dt>
|
---|
345 | </dl>
|
---|
346 | </div>
|
---|
347 | <div class="SECT1">
|
---|
348 | <h2 class="SECT1"><a name="INTRO" id="INTRO">1.
|
---|
349 | Introduction</a></h2>
|
---|
350 | <p>In the olden days of teletype terminals, terminals were away
|
---|
351 | from computers and were connected to them through serial cables.
|
---|
352 | The terminals could be configured by sending a series of bytes. All
|
---|
353 | the capabilities (such as moving the cursor to a new location,
|
---|
354 | erasing part of the screen, scrolling the screen, changing modes
|
---|
355 | etc.) of terminals could be accessed through these series of bytes.
|
---|
356 | These control seeuqnces are usually called escape sequences,
|
---|
357 | because they start with an escape(0x1B) character. Even today, with
|
---|
358 | proper emulation, we can send escape sequences to the emulator and
|
---|
359 | achieve the same effect on a terminal window.</p>
|
---|
360 | <p>Suppose you wanted to print a line in color. Try typing this on
|
---|
361 | your console.</p>
|
---|
362 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
363 | <tr>
|
---|
364 | <td>
|
---|
365 | <pre class="PROGRAMLISTING">
|
---|
366 | <font color="#000000">echo "^[[0;31;40mIn Color"</font>
|
---|
367 | </pre></td>
|
---|
368 | </tr>
|
---|
369 | </table>
|
---|
370 | <p>The first character is an escape character, which looks like two
|
---|
371 | characters ^ and [. To be able to print it, you have to press
|
---|
372 | CTRL+V and then the ESC key. All the others are normal printable
|
---|
373 | characters. You should be able to see the string "In Color" in red.
|
---|
374 | It stays that way and to revert back to the original mode type
|
---|
375 | this.</p>
|
---|
376 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
377 | <tr>
|
---|
378 | <td>
|
---|
379 | <pre class="PROGRAMLISTING">
|
---|
380 | <font color="#000000">echo "^[[0;37;40m"</font>
|
---|
381 | </pre></td>
|
---|
382 | </tr>
|
---|
383 | </table>
|
---|
384 | <p>Now, what do these magic characters mean? Difficult to
|
---|
385 | comprehend? They might even be different for different terminals.
|
---|
386 | So the designers of UNIX invented a mechanism named <var class=
|
---|
387 | "LITERAL">termcap</var>. It is a file that lists all the
|
---|
388 | capabilities of a particular terminal, along with the escape
|
---|
389 | sequences needed to achieve a particular effect. In the later
|
---|
390 | years, this was replaced by <var class="LITERAL">terminfo</var>.
|
---|
391 | Without delving too much into details, this mechanism allows
|
---|
392 | application programs to query the terminfo database and obtain the
|
---|
393 | control characters to be sent to a terminal or terminal
|
---|
394 | emulator.</p>
|
---|
395 | <div class="SECT2">
|
---|
396 | <hr>
|
---|
397 | <h3 class="SECT2"><a name="WHATIS" id="WHATIS">1.1. What is
|
---|
398 | NCURSES?</a></h3>
|
---|
399 | <p>You might be wondering, what the import of all this technical
|
---|
400 | gibberish is. In the above scenario, every application program is
|
---|
401 | supposed to query the terminfo and perform the necessary stuff
|
---|
402 | (sending control characters etc.). It soon became difficult to
|
---|
403 | manage this complexity and this gave birth to 'CURSES'. Curses is a
|
---|
404 | pun on the name "cursor optimization". The Curses library forms a
|
---|
405 | wrapper over working with raw terminal codes, and provides highly
|
---|
406 | flexible and efficient API (Application Programming Interface). It
|
---|
407 | provides functions to move the cursor, create windows, produce
|
---|
408 | colors, play with mouse etc. The application programs need not
|
---|
409 | worry about the underlying terminal capabilities.</p>
|
---|
410 | <p>So what is NCURSES? NCURSES is a clone of the original System V
|
---|
411 | Release 4.0 (SVr4) curses. It is a freely distributable library,
|
---|
412 | fully compatible with older version of curses. In short, it is a
|
---|
413 | library of functions that manages an application's display on
|
---|
414 | character-cell terminals. In the remainder of the document, the
|
---|
415 | terms curses and ncurses are used interchangeably.</p>
|
---|
416 | <p>A detailed history of NCURSES can be found in the NEWS file from
|
---|
417 | the source distribution. The current package is maintained by
|
---|
418 | <a href="mailto:dickey@his.com" target="_top">Thomas Dickey</a>.
|
---|
419 | You can contact the maintainers at <a href=
|
---|
420 | "mailto:bug-ncurses@gnu.org" target=
|
---|
421 | "_top">bug-ncurses@gnu.org</a>.</p>
|
---|
422 | </div>
|
---|
423 | <div class="SECT2">
|
---|
424 | <hr>
|
---|
425 | <h3 class="SECT2"><a name="WHATCANWEDO" id="WHATCANWEDO">1.2. What
|
---|
426 | we can do with NCURSES</a></h3>
|
---|
427 | <p>NCURSES not only creates a wrapper over terminal capabilities,
|
---|
428 | but also gives a robust framework to create nice looking UI (User
|
---|
429 | Interface)s in text mode. It provides functions to create windows
|
---|
430 | etc. Its sister libraries panel, menu and form provide an extension
|
---|
431 | to the basic curses library. These libraries usually come along
|
---|
432 | with curses. One can create applications that contain multiple
|
---|
433 | windows, menus, panels and forms. Windows can be managed
|
---|
434 | independently, can provide 'scrollability' and even can be
|
---|
435 | hidden.</p>
|
---|
436 | <p>Menus provide the user with an easy command selection option.
|
---|
437 | Forms allow the creation of easy-to-use data entry and display
|
---|
438 | windows. Panels extend the capabilities of ncurses to deal with
|
---|
439 | overlapping and stacked windows.</p>
|
---|
440 | <p>These are just some of the basic things we can do with ncurses.
|
---|
441 | As we move along, We will see all the capabilities of these
|
---|
442 | libraries.</p>
|
---|
443 | </div>
|
---|
444 | <div class="SECT2">
|
---|
445 | <hr>
|
---|
446 | <h3 class="SECT2"><a name="WHERETOGETIT" id="WHERETOGETIT">1.3.
|
---|
447 | Where to get it</a></h3>
|
---|
448 | <p>All right, now that you know what you can do with ncurses, you
|
---|
449 | must be rearing to get started. NCURSES is usually shipped with
|
---|
450 | your installation. In case you don't have the library or want to
|
---|
451 | compile it on your own, read on.</p>
|
---|
452 | <p><em>Compiling the package</em></p>
|
---|
453 | <p>NCURSES can be obtained from <a href=
|
---|
454 | "ftp://ftp.gnu.org/pub/gnu/ncurses/ncurses.tar.gz" target=
|
---|
455 | "_top">ftp://ftp.gnu.org/pub/gnu/ncurses/ncurses.tar.gz</a> or any
|
---|
456 | of the ftp sites mentioned in <a href=
|
---|
457 | "http://www.gnu.org/order/ftp.html" target=
|
---|
458 | "_top">http://www.gnu.org/order/ftp.html</a>.</p>
|
---|
459 | <p>Read the README and INSTALL files for details on to how to
|
---|
460 | install it. It usually involves the following operations.</p>
|
---|
461 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
462 | <tr>
|
---|
463 | <td>
|
---|
464 | <pre class="PROGRAMLISTING">
|
---|
465 | <font color=
|
---|
466 | "#000000"> tar zxvf ncurses<version>.tar.gz # unzip and untar the archive
|
---|
467 | cd ncurses<version> # cd to the directory
|
---|
468 | ./configure # configure the build according to your
|
---|
469 | # environment
|
---|
470 | make # make it
|
---|
471 | su root # become root
|
---|
472 | make install # install it</font>
|
---|
473 | </pre></td>
|
---|
474 | </tr>
|
---|
475 | </table>
|
---|
476 | <p><em>Using the RPM</em></p>
|
---|
477 | <p>NCURSES RPM can be found and downloaded from <a href=
|
---|
478 | "http://rpmfind.net" target="_top">http://rpmfind.net</a> . The RPM
|
---|
479 | can be installed with the following command after becoming
|
---|
480 | root.</p>
|
---|
481 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
482 | <tr>
|
---|
483 | <td>
|
---|
484 | <pre class="PROGRAMLISTING">
|
---|
485 | <font color="#000000"> rpm -i <downloaded rpm></font>
|
---|
486 | </pre></td>
|
---|
487 | </tr>
|
---|
488 | </table>
|
---|
489 | </div>
|
---|
490 | <div class="SECT2">
|
---|
491 | <hr>
|
---|
492 | <h3 class="SECT2"><a name="PURPOSE" id="PURPOSE">1.4. Purpose/Scope
|
---|
493 | of the document</a></h3>
|
---|
494 | <p>This document is intended to be a "All in One" guide for
|
---|
495 | programming with ncurses and its sister libraries. We graduate from
|
---|
496 | a simple "Hello World" program to more complex form manipulation.
|
---|
497 | No prior experience in ncurses is assumed. The writing is informal,
|
---|
498 | but a lot of detail is provided for each of the examples.</p>
|
---|
499 | </div>
|
---|
500 | <div class="SECT2">
|
---|
501 | <hr>
|
---|
502 | <h3 class="SECT2"><a name="ABOUTPROGRAMS" id="ABOUTPROGRAMS">1.5.
|
---|
503 | About the Programs</a></h3>
|
---|
504 | <p>All the programs in the document are available in zipped form
|
---|
505 | <a href=
|
---|
506 | "http://www.tldp.org/HOWTO/NCURSES-Programming-HOWTO/ncurses_programs.tar.gz"
|
---|
507 | target="_top">here</a>. Unzip and untar it. The directory structure
|
---|
508 | looks like this.</p>
|
---|
509 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
510 | <tr>
|
---|
511 | <td>
|
---|
512 | <pre class="PROGRAMLISTING">
|
---|
513 | <font color="#000000">ncurses
|
---|
514 | |
|
---|
515 | |----> JustForFun -- just for fun programs
|
---|
516 | |----> basics -- basic programs
|
---|
517 | |----> demo -- output files go into this directory after make
|
---|
518 | | |
|
---|
519 | | |----> exe -- exe files of all example programs
|
---|
520 | |----> forms -- programs related to form library
|
---|
521 | |----> menus -- programs related to menus library
|
---|
522 | |----> panels -- programs related to panels library
|
---|
523 | |----> perl -- perl equivalents of the examples (contributed
|
---|
524 | | by Anuradha Ratnaweera)
|
---|
525 | |----> Makefile -- the top level Makefile
|
---|
526 | |----> README -- the top level README file. contains instructions
|
---|
527 | |----> COPYING -- copyright notice</font>
|
---|
528 | </pre></td>
|
---|
529 | </tr>
|
---|
530 | </table>
|
---|
531 | <p>The individual directories contain the following files.</p>
|
---|
532 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
533 | <tr>
|
---|
534 | <td>
|
---|
535 | <pre class="PROGRAMLISTING">
|
---|
536 | <font color="#000000">Description of files in each directory
|
---|
537 | --------------------------------------
|
---|
538 | JustForFun
|
---|
539 | |
|
---|
540 | |----> hanoi.c -- The Towers of Hanoi Solver
|
---|
541 | |----> life.c -- The Game of Life demo
|
---|
542 | |----> magic.c -- An Odd Order Magic Square builder
|
---|
543 | |----> queens.c -- The famous N-Queens Solver
|
---|
544 | |----> shuffle.c -- A fun game, if you have time to kill
|
---|
545 | |----> tt.c -- A very trivial typing tutor
|
---|
546 |
|
---|
547 | basics
|
---|
548 | |
|
---|
549 | |----> acs_vars.c -- ACS_ variables example
|
---|
550 | |----> hello_world.c -- Simple "Hello World" Program
|
---|
551 | |----> init_func_example.c -- Initialization functions example
|
---|
552 | |----> key_code.c -- Shows the scan code of the key pressed
|
---|
553 | |----> mouse_menu.c -- A menu accessible by mouse
|
---|
554 | |----> other_border.c -- Shows usage of other border functions apa
|
---|
555 | | -- rt from box()
|
---|
556 | |----> printw_example.c -- A very simple printw() example
|
---|
557 | |----> scanw_example.c -- A very simple getstr() example
|
---|
558 | |----> simple_attr.c -- A program that can print a c file with
|
---|
559 | | -- comments in attribute
|
---|
560 | |----> simple_color.c -- A simple example demonstrating colors
|
---|
561 | |----> simple_key.c -- A menu accessible with keyboard UP, DOWN
|
---|
562 | | -- arrows
|
---|
563 | |----> temp_leave.c -- Demonstrates temporarily leaving curses mode
|
---|
564 | |----> win_border.c -- Shows Creation of windows and borders
|
---|
565 | |----> with_chgat.c -- chgat() usage example
|
---|
566 |
|
---|
567 | forms
|
---|
568 | |
|
---|
569 | |----> form_attrib.c -- Usage of field attributes
|
---|
570 | |----> form_options.c -- Usage of field options
|
---|
571 | |----> form_simple.c -- A simple form example
|
---|
572 | |----> form_win.c -- Demo of windows associated with forms
|
---|
573 |
|
---|
574 | menus
|
---|
575 | |
|
---|
576 | |----> menu_attrib.c -- Usage of menu attributes
|
---|
577 | |----> menu_item_data.c -- Usage of item_name() etc.. functions
|
---|
578 | |----> menu_multi_column.c -- Creates multi columnar menus
|
---|
579 | |----> menu_scroll.c -- Demonstrates scrolling capability of menus
|
---|
580 | |----> menu_simple.c -- A simple menu accessed by arrow keys
|
---|
581 | |----> menu_toggle.c -- Creates multi valued menus and explains
|
---|
582 | | -- REQ_TOGGLE_ITEM
|
---|
583 | |----> menu_userptr.c -- Usage of user pointer
|
---|
584 | |----> menu_win.c -- Demo of windows associated with menus
|
---|
585 |
|
---|
586 | panels
|
---|
587 | |
|
---|
588 | |----> panel_browse.c -- Panel browsing through tab. Usage of user
|
---|
589 | | -- pointer
|
---|
590 | |----> panel_hide.c -- Hiding and Un hiding of panels
|
---|
591 | |----> panel_resize.c -- Moving and resizing of panels
|
---|
592 | |----> panel_simple.c -- A simple panel example
|
---|
593 |
|
---|
594 | perl
|
---|
595 | |----> 01-10.pl -- Perl equivalents of first ten example programs</font>
|
---|
596 | </pre></td>
|
---|
597 | </tr>
|
---|
598 | </table>
|
---|
599 | <p>There is a top level Makefile included in the main directory. It
|
---|
600 | builds all the files and puts the ready-to-use exes in demo/exe
|
---|
601 | directory. You can also do selective make by going into the
|
---|
602 | corresponding directory. Each directory contains a README file
|
---|
603 | explaining the purpose of each c file in the directory.</p>
|
---|
604 | <p>For every example, I have included path name for the file
|
---|
605 | relative to the examples directory.</p>
|
---|
606 | <p>If you prefer browsing individual programs, point your browser
|
---|
607 | to <a href=
|
---|
608 | "http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/ncurses_programs/"
|
---|
609 | target=
|
---|
610 | "_top">http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/ncurses_programs/</a></p>
|
---|
611 | <p>All the programs are released under the same license that is
|
---|
612 | used by ncurses (MIT-style). This gives you the ability to do
|
---|
613 | pretty much anything other than claiming them as yours. Feel free
|
---|
614 | to use them in your programs as appropriate.</p>
|
---|
615 | </div>
|
---|
616 | <div class="SECT2">
|
---|
617 | <hr>
|
---|
618 | <h3 class="SECT2"><a name="OTHERFORMATS" id="OTHERFORMATS">1.6.
|
---|
619 | Other Formats of the document</a></h3>
|
---|
620 | <p>This howto is also availabe in various other formats on the
|
---|
621 | tldp.org site. Here are the links to other formats of this
|
---|
622 | document.</p>
|
---|
623 | <div class="SECT3">
|
---|
624 | <hr>
|
---|
625 | <h4 class="SECT3"><a name="LISTFORMATS" id="LISTFORMATS">1.6.1.
|
---|
626 | Readily available formats from tldp.org</a></h4>
|
---|
627 | <ul>
|
---|
628 | <li>
|
---|
629 | <p><a href=
|
---|
630 | "http://www.ibiblio.org/pub/Linux/docs/HOWTO/other-formats/pdf/NCURSES-Programming-HOWTO.pdf"
|
---|
631 | target="_top">Acrobat PDF Format</a></p>
|
---|
632 | </li>
|
---|
633 | <li>
|
---|
634 | <p><a href=
|
---|
635 | "http://www.ibiblio.org/pub/Linux/docs/HOWTO/other-formats/ps/NCURSES-Programming-HOWTO.ps.gz"
|
---|
636 | target="_top">PostScript Format</a></p>
|
---|
637 | </li>
|
---|
638 | <li>
|
---|
639 | <p><a href=
|
---|
640 | "http://www.ibiblio.org/pub/Linux/docs/HOWTO/other-formats/html/NCURSES-Programming-HOWTO-html.tar.gz"
|
---|
641 | target="_top">In Multiple HTML pages</a></p>
|
---|
642 | </li>
|
---|
643 | <li>
|
---|
644 | <p><a href=
|
---|
645 | "http://www.ibiblio.org/pub/Linux/docs/HOWTO/other-formats/html_single/NCURSES-Programming-HOWTO.html"
|
---|
646 | target="_top">In One big HTML format</a></p>
|
---|
647 | </li>
|
---|
648 | </ul>
|
---|
649 | </div>
|
---|
650 | <div class="SECT3">
|
---|
651 | <hr>
|
---|
652 | <h4 class="SECT3"><a name="BUILDSOURCE" id="BUILDSOURCE">1.6.2.
|
---|
653 | Building from source</a></h4>
|
---|
654 | <p>If above links are broken or if you want to experiment with sgml
|
---|
655 | read on.</p>
|
---|
656 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
657 | <tr>
|
---|
658 | <td>
|
---|
659 | <pre class="PROGRAMLISTING">
|
---|
660 | <font color=
|
---|
661 | "#000000"> Get both the source and the tar,gzipped programs, available at
|
---|
662 | http://cvsview.tldp.org/index.cgi/LDP/howto/docbook/
|
---|
663 | NCURSES-HOWTO/NCURSES-Programming-HOWTO.sgml
|
---|
664 | http://cvsview.tldp.org/index.cgi/LDP/howto/docbook/
|
---|
665 | NCURSES-HOWTO/ncurses_programs.tar.gz
|
---|
666 |
|
---|
667 | Unzip ncurses_programs.tar.gz with
|
---|
668 | tar zxvf ncurses_programs.tar.gz
|
---|
669 |
|
---|
670 | Use jade to create various formats. For example if you just want to create
|
---|
671 | the multiple html files, you would use
|
---|
672 | jade -t sgml -i html -d <path to docbook html stylesheet>
|
---|
673 | NCURSES-Programming-HOWTO.sgml
|
---|
674 | to get pdf, first create a single html file of the HOWTO with
|
---|
675 | jade -t sgml -i html -d <path to docbook html stylesheet> -V nochunks
|
---|
676 | NCURSES-Programming-HOWTO.sgml > NCURSES-ONE-BIG-FILE.html
|
---|
677 | then use htmldoc to get pdf file with
|
---|
678 | htmldoc --size universal -t pdf --firstpage p1 -f <output file name.pdf>
|
---|
679 | NCURSES-ONE-BIG-FILE.html
|
---|
680 | for ps, you would use
|
---|
681 | htmldoc --size universal -t ps --firstpage p1 -f <output file name.ps>
|
---|
682 | NCURSES-ONE-BIG-FILE.html</font>
|
---|
683 | </pre></td>
|
---|
684 | </tr>
|
---|
685 | </table>
|
---|
686 | <p>See <a href="http://www.tldp.org/LDP/LDP-Author-Guide/" target=
|
---|
687 | "_top">LDP Author guide</a> for more details. If all else failes,
|
---|
688 | mail me at <a href="ppadala@gmail.com" target=
|
---|
689 | "_top">ppadala@gmail.com</a></p>
|
---|
690 | </div>
|
---|
691 | </div>
|
---|
692 | <div class="SECT2">
|
---|
693 | <hr>
|
---|
694 | <h3 class="SECT2"><a name="CREDITS" id="CREDITS">1.7.
|
---|
695 | Credits</a></h3>
|
---|
696 | <p>I thank <a href="mailto:sharath_1@usa.net" target=
|
---|
697 | "_top">Sharath</a> and Emre Akbas for helping me with few sections.
|
---|
698 | The introduction was initially written by sharath. I rewrote it
|
---|
699 | with few excerpts taken from his initial work. Emre helped in
|
---|
700 | writing printw and scanw sections.</p>
|
---|
701 | <p>Perl equivalents of the example programs are contributed by
|
---|
702 | <a href="mailto:Aratnaweera@virtusa.com" target="_top">Anuradha
|
---|
703 | Ratnaweera</a>.</p>
|
---|
704 | <p>Then comes <a href="mailto:parimi@ece.arizona.edu" target=
|
---|
705 | "_top">Ravi Parimi</a>, my dearest friend, who has been on this
|
---|
706 | project before even one line was written. He constantly bombarded
|
---|
707 | me with suggestions and patiently reviewed the whole text. He also
|
---|
708 | checked each program on Linux and Solaris.</p>
|
---|
709 | </div>
|
---|
710 | <div class="SECT2">
|
---|
711 | <hr>
|
---|
712 | <h3 class="SECT2"><a name="WISHLIST" id="WISHLIST">1.8. Wish
|
---|
713 | List</a></h3>
|
---|
714 | <p>This is the wish list, in the order of priority. If you have a
|
---|
715 | wish or you want to work on completing the wish, mail <a href=
|
---|
716 | "mailto:ppadala@gmail.com" target="_top">me</a>.</p>
|
---|
717 | <ul>
|
---|
718 | <li>
|
---|
719 | <p>Add examples to last parts of forms section.</p>
|
---|
720 | </li>
|
---|
721 | <li>
|
---|
722 | <p>Prepare a Demo showing all the programs and allow the user to
|
---|
723 | browse through description of each program. Let the user compile
|
---|
724 | and see the program in action. A dialog based interface is
|
---|
725 | preferred.</p>
|
---|
726 | </li>
|
---|
727 | <li>
|
---|
728 | <p>Add debug info. _tracef, _tracemouse stuff.</p>
|
---|
729 | </li>
|
---|
730 | <li>
|
---|
731 | <p>Accessing termcap, terminfo using functions provided by ncurses
|
---|
732 | package.</p>
|
---|
733 | </li>
|
---|
734 | <li>
|
---|
735 | <p>Working on two terminals simultaneously.</p>
|
---|
736 | </li>
|
---|
737 | <li>
|
---|
738 | <p>Add more stuff to miscellaneous section.</p>
|
---|
739 | </li>
|
---|
740 | </ul>
|
---|
741 | </div>
|
---|
742 | <div class="SECT2">
|
---|
743 | <hr>
|
---|
744 | <h3 class="SECT2"><a name="COPYRIGHT" id="COPYRIGHT">1.9.
|
---|
745 | Copyright</a></h3>
|
---|
746 | <p>Copyright © 2001 by Pradeep Padala.</p>
|
---|
747 | <p>Permission is hereby granted, free of charge, to any person
|
---|
748 | obtaining a copy of this software and associated documentation
|
---|
749 | files (the "Software"), to deal in the Software without
|
---|
750 | restriction, including without limitation the rights to use, copy,
|
---|
751 | modify, merge, publish, distribute, distribute with modifications,
|
---|
752 | sublicense, and/or sell copies of the Software, and to permit
|
---|
753 | persons to whom the Software is furnished to do so, subject to the
|
---|
754 | following conditions:</p>
|
---|
755 | <p>The above copyright notice and this permission notice shall be
|
---|
756 | included in all copies or substantial portions of the Software.</p>
|
---|
757 | <p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
---|
758 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
---|
759 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
---|
760 | NONINFRINGEMENT. IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE
|
---|
761 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
---|
762 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
---|
763 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
---|
764 | SOFTWARE.</p>
|
---|
765 | <p>Except as contained in this notice, the name(s) of the above
|
---|
766 | copyright holders shall not be used in advertising or otherwise to
|
---|
767 | promote the sale, use or other dealings in this Software without
|
---|
768 | prior written authorization.</p>
|
---|
769 | </div>
|
---|
770 | </div>
|
---|
771 | <div class="SECT1">
|
---|
772 | <hr>
|
---|
773 | <h2 class="SECT1"><a name="HELLOWORLD" id="HELLOWORLD">2. Hello
|
---|
774 | World !!!</a></h2>
|
---|
775 | <p>Welcome to the world of curses. Before we plunge into the
|
---|
776 | library and look into its various features, let's write a simple
|
---|
777 | program and say hello to the world.</p>
|
---|
778 | <div class="SECT2">
|
---|
779 | <hr>
|
---|
780 | <h3 class="SECT2"><a name="COMPILECURSES" id="COMPILECURSES">2.1.
|
---|
781 | Compiling With the NCURSES Library</a></h3>
|
---|
782 | <p>To use ncurses library functions, you have to include ncurses.h
|
---|
783 | in your programs. To link the program with ncurses the flag
|
---|
784 | -lncurses should be added.</p>
|
---|
785 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
786 | <tr>
|
---|
787 | <td>
|
---|
788 | <pre class="PROGRAMLISTING">
|
---|
789 | <font color="#000000"> #include <ncurses.h>
|
---|
790 | .
|
---|
791 | .
|
---|
792 | .
|
---|
793 |
|
---|
794 | compile and link: gcc <program file> -lncurses</font>
|
---|
795 | </pre></td>
|
---|
796 | </tr>
|
---|
797 | </table>
|
---|
798 | <div class="EXAMPLE"><a name="BHW" id="BHW"></a>
|
---|
799 | <p><b>Example 1. The Hello World !!! Program</b></p>
|
---|
800 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
801 | <tr>
|
---|
802 | <td>
|
---|
803 | <pre class="PROGRAMLISTING">
|
---|
804 | <font color="#000000"><span class=
|
---|
805 | "INLINEMEDIAOBJECT">#include <ncurses.h>
|
---|
806 |
|
---|
807 | int main()
|
---|
808 | {
|
---|
809 | initscr(); /* Start curses mode */
|
---|
810 | printw("Hello World !!!"); /* Print Hello World */
|
---|
811 | refresh(); /* Print it on to the real screen */
|
---|
812 | getch(); /* Wait for user input */
|
---|
813 | endwin(); /* End curses mode */
|
---|
814 |
|
---|
815 | return 0;
|
---|
816 | }</span></font>
|
---|
817 | </pre></td>
|
---|
818 | </tr>
|
---|
819 | </table>
|
---|
820 | </div>
|
---|
821 | </div>
|
---|
822 | <div class="SECT2">
|
---|
823 | <hr>
|
---|
824 | <h3 class="SECT2"><a name="DISSECTION" id="DISSECTION">2.2.
|
---|
825 | Dissection</a></h3>
|
---|
826 | <p>The above program prints "Hello World !!!" to the screen and
|
---|
827 | exits. This program shows how to initialize curses and do screen
|
---|
828 | manipulation and end curses mode. Let's dissect it line by
|
---|
829 | line.</p>
|
---|
830 | <div class="SECT3">
|
---|
831 | <hr>
|
---|
832 | <h4 class="SECT3"><a name="ABOUT-INITSCR" id="ABOUT-INITSCR">2.2.1.
|
---|
833 | About initscr()</a></h4>
|
---|
834 | <p>The function initscr() initializes the terminal in curses mode.
|
---|
835 | In some implementations, it clears the screen and presents a blank
|
---|
836 | screen. To do any screen manipulation using curses package this has
|
---|
837 | to be called first. This function initializes the curses system and
|
---|
838 | allocates memory for our present window (called <var class=
|
---|
839 | "LITERAL">stdscr</var>) and some other data-structures. Under
|
---|
840 | extreme cases this function might fail due to insufficient memory
|
---|
841 | to allocate memory for curses library's data structures.</p>
|
---|
842 | <p>After this is done, we can do a variety of initializations to
|
---|
843 | customize our curses settings. These details will be explained
|
---|
844 | <a href="#INIT">later</a> .</p>
|
---|
845 | </div>
|
---|
846 | <div class="SECT3">
|
---|
847 | <hr>
|
---|
848 | <h4 class="SECT3"><a name="MYST-REFRESH" id="MYST-REFRESH">2.2.2.
|
---|
849 | The mysterious refresh()</a></h4>
|
---|
850 | <p>The next line printw prints the string "Hello World !!!" on to
|
---|
851 | the screen. This function is analogous to normal printf in all
|
---|
852 | respects except that it prints the data on a window called stdscr
|
---|
853 | at the current (y,x) co-ordinates. Since our present co-ordinates
|
---|
854 | are at 0,0 the string is printed at the left hand corner of the
|
---|
855 | window.</p>
|
---|
856 | <p>This brings us to that mysterious refresh(). Well, when we
|
---|
857 | called printw the data is actually written to an imaginary window,
|
---|
858 | which is not updated on the screen yet. The job of printw is to
|
---|
859 | update a few flags and data structures and write the data to a
|
---|
860 | buffer corresponding to stdscr. In order to show it on the screen,
|
---|
861 | we need to call refresh() and tell the curses system to dump the
|
---|
862 | contents on the screen.</p>
|
---|
863 | <p>The philosophy behind all this is to allow the programmer to do
|
---|
864 | multiple updates on the imaginary screen or windows and do a
|
---|
865 | refresh once all his screen update is done. refresh() checks the
|
---|
866 | window and updates only the portion which has been changed. This
|
---|
867 | improves performance and offers greater flexibility too. But, it is
|
---|
868 | sometimes frustrating to beginners. A common mistake committed by
|
---|
869 | beginners is to forget to call refresh() after they did some update
|
---|
870 | through printw() class of functions. I still forget to add it
|
---|
871 | sometimes :-)</p>
|
---|
872 | </div>
|
---|
873 | <div class="SECT3">
|
---|
874 | <hr>
|
---|
875 | <h4 class="SECT3"><a name="ABOUT-ENDWIN" id="ABOUT-ENDWIN">2.2.3.
|
---|
876 | About endwin()</a></h4>
|
---|
877 | <p>And finally don't forget to end the curses mode. Otherwise your
|
---|
878 | terminal might behave strangely after the program quits. endwin()
|
---|
879 | frees the memory taken by curses sub-system and its data structures
|
---|
880 | and puts the terminal in normal mode. This function must be called
|
---|
881 | after you are done with the curses mode.</p>
|
---|
882 | </div>
|
---|
883 | </div>
|
---|
884 | </div>
|
---|
885 | <div class="SECT1">
|
---|
886 | <hr>
|
---|
887 | <h2 class="SECT1"><a name="GORY" id="GORY">3. The Gory
|
---|
888 | Details</a></h2>
|
---|
889 | <p>Now that we have seen how to write a simple curses program let's
|
---|
890 | get into the details. There are many functions that help customize
|
---|
891 | what you see on screen and many features which can be put to full
|
---|
892 | use.</p>
|
---|
893 | <p>Here we go...</p>
|
---|
894 | </div>
|
---|
895 | <div class="SECT1">
|
---|
896 | <hr>
|
---|
897 | <h2 class="SECT1"><a name="INIT" id="INIT">4.
|
---|
898 | Initialization</a></h2>
|
---|
899 | <p>We now know that to initialize curses system the function
|
---|
900 | initscr() has to be called. There are functions which can be called
|
---|
901 | after this initialization to customize our curses session. We may
|
---|
902 | ask the curses system to set the terminal in raw mode or initialize
|
---|
903 | color or initialize the mouse etc.. Let's discuss some of the
|
---|
904 | functions that are normally called immediately after initscr();</p>
|
---|
905 | <div class="SECT2">
|
---|
906 | <hr>
|
---|
907 | <h3 class="SECT2"><a name="ABOUTINIT" id="ABOUTINIT">4.1.
|
---|
908 | Initialization functions</a></h3>
|
---|
909 | </div>
|
---|
910 | <div class="SECT2">
|
---|
911 | <hr>
|
---|
912 | <h3 class="SECT2"><a name="RAWCBREAK" id="RAWCBREAK">4.2. raw() and
|
---|
913 | cbreak()</a></h3>
|
---|
914 | <p>Normally the terminal driver buffers the characters a user types
|
---|
915 | until a new line or carriage return is encountered. But most
|
---|
916 | programs require that the characters be available as soon as the
|
---|
917 | user types them. The above two functions are used to disable line
|
---|
918 | buffering. The difference between these two functions is in the way
|
---|
919 | control characters like suspend (CTRL-Z), interrupt and quit
|
---|
920 | (CTRL-C) are passed to the program. In the raw() mode these
|
---|
921 | characters are directly passed to the program without generating a
|
---|
922 | signal. In the <var class="LITERAL">cbreak()</var> mode these
|
---|
923 | control characters are interpreted as any other character by the
|
---|
924 | terminal driver. I personally prefer to use raw() as I can exercise
|
---|
925 | greater control over what the user does.</p>
|
---|
926 | </div>
|
---|
927 | <div class="SECT2">
|
---|
928 | <hr>
|
---|
929 | <h3 class="SECT2"><a name="ECHONOECHO" id="ECHONOECHO">4.3. echo()
|
---|
930 | and noecho()</a></h3>
|
---|
931 | <p>These functions control the echoing of characters typed by the
|
---|
932 | user to the terminal. <var class="LITERAL">noecho()</var> switches
|
---|
933 | off echoing. The reason you might want to do this is to gain more
|
---|
934 | control over echoing or to suppress unnecessary echoing while
|
---|
935 | taking input from the user through the getch() etc. functions. Most
|
---|
936 | of the interactive programs call <var class=
|
---|
937 | "LITERAL">noecho()</var> at initialization and do the echoing of
|
---|
938 | characters in a controlled manner. It gives the programmer the
|
---|
939 | flexibility of echoing characters at any place in the window
|
---|
940 | without updating current (y,x) co-ordinates.</p>
|
---|
941 | </div>
|
---|
942 | <div class="SECT2">
|
---|
943 | <hr>
|
---|
944 | <h3 class="SECT2"><a name="KEYPAD" id="KEYPAD">4.4.
|
---|
945 | keypad()</a></h3>
|
---|
946 | <p>This is my favorite initialization function. It enables the
|
---|
947 | reading of function keys like F1, F2, arrow keys etc. Almost every
|
---|
948 | interactive program enables this, as arrow keys are a major part of
|
---|
949 | any User Interface. Do <var class="LITERAL">keypad(stdscr,
|
---|
950 | TRUE)</var> to enable this feature for the regular screen (stdscr).
|
---|
951 | You will learn more about key management in later sections of this
|
---|
952 | document.</p>
|
---|
953 | </div>
|
---|
954 | <div class="SECT2">
|
---|
955 | <hr>
|
---|
956 | <h3 class="SECT2"><a name="HALFDELAY" id="HALFDELAY">4.5.
|
---|
957 | halfdelay()</a></h3>
|
---|
958 | <p>This function, though not used very often, is a useful one at
|
---|
959 | times. halfdelay()is called to enable the half-delay mode, which is
|
---|
960 | similar to the cbreak() mode in that characters typed are
|
---|
961 | immediately available to program. However, it waits for 'X' tenths
|
---|
962 | of a second for input and then returns ERR, if no input is
|
---|
963 | available. 'X' is the timeout value passed to the function
|
---|
964 | halfdelay(). This function is useful when you want to ask the user
|
---|
965 | for input, and if he doesn't respond with in certain time, we can
|
---|
966 | do some thing else. One possible example is a timeout at the
|
---|
967 | password prompt.</p>
|
---|
968 | </div>
|
---|
969 | <div class="SECT2">
|
---|
970 | <hr>
|
---|
971 | <h3 class="SECT2"><a name="MISCINIT" id="MISCINIT">4.6.
|
---|
972 | Miscellaneous Initialization functions</a></h3>
|
---|
973 | <p>There are few more functions which are called at initialization
|
---|
974 | to customize curses behavior. They are not used as extensively as
|
---|
975 | those mentioned above. Some of them are explained where
|
---|
976 | appropriate.</p>
|
---|
977 | </div>
|
---|
978 | <div class="SECT2">
|
---|
979 | <hr>
|
---|
980 | <h3 class="SECT2"><a name="INITEX" id="INITEX">4.7. An
|
---|
981 | Example</a></h3>
|
---|
982 | <p>Let's write a program which will clarify the usage of these
|
---|
983 | functions.</p>
|
---|
984 | <div class="EXAMPLE"><a name="BINFU" id="BINFU"></a>
|
---|
985 | <p><b>Example 2. Initialization Function Usage example</b></p>
|
---|
986 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
987 | <tr>
|
---|
988 | <td>
|
---|
989 | <pre class="PROGRAMLISTING">
|
---|
990 | <font color="#000000"><span class=
|
---|
991 | "INLINEMEDIAOBJECT">#include <ncurses.h>
|
---|
992 |
|
---|
993 | int main()
|
---|
994 | { int ch;
|
---|
995 |
|
---|
996 | initscr(); /* Start curses mode */
|
---|
997 | raw(); /* Line buffering disabled */
|
---|
998 | keypad(stdscr, TRUE); /* We get F1, F2 etc.. */
|
---|
999 | noecho(); /* Don't echo() while we do getch */
|
---|
1000 |
|
---|
1001 | printw("Type any character to see it in bold\n");
|
---|
1002 | ch = getch(); /* If raw() hadn't been called
|
---|
1003 | * we have to press enter before it
|
---|
1004 | * gets to the program */
|
---|
1005 | if(ch == KEY_F(1)) /* Without keypad enabled this will */
|
---|
1006 | printw("F1 Key pressed");/* not get to us either */
|
---|
1007 | /* Without noecho() some ugly escape
|
---|
1008 | * charachters might have been printed
|
---|
1009 | * on screen */
|
---|
1010 | else
|
---|
1011 | { printw("The pressed key is ");
|
---|
1012 | attron(A_BOLD);
|
---|
1013 | printw("%c", ch);
|
---|
1014 | attroff(A_BOLD);
|
---|
1015 | }
|
---|
1016 | refresh(); /* Print it on to the real screen */
|
---|
1017 | getch(); /* Wait for user input */
|
---|
1018 | endwin(); /* End curses mode */
|
---|
1019 |
|
---|
1020 | return 0;
|
---|
1021 | }</span></font>
|
---|
1022 | </pre></td>
|
---|
1023 | </tr>
|
---|
1024 | </table>
|
---|
1025 | </div>
|
---|
1026 | <p>This program is self-explanatory. But I used functions which
|
---|
1027 | aren't explained yet. The function <var class=
|
---|
1028 | "LITERAL">getch()</var> is used to get a character from user. It is
|
---|
1029 | equivalent to normal <var class="LITERAL">getchar()</var> except
|
---|
1030 | that we can disable the line buffering to avoid <enter> after
|
---|
1031 | input. Look for more about <var class="LITERAL">getch()</var>and
|
---|
1032 | reading keys in the <a href="#KEYS">key management section</a> .
|
---|
1033 | The functions attron and attroff are used to switch some attributes
|
---|
1034 | on and off respectively. In the example I used them to print the
|
---|
1035 | character in bold. These functions are explained in detail
|
---|
1036 | later.</p>
|
---|
1037 | </div>
|
---|
1038 | </div>
|
---|
1039 | <div class="SECT1">
|
---|
1040 | <hr>
|
---|
1041 | <h2 class="SECT1"><a name="AWORDWINDOWS" id="AWORDWINDOWS">5. A
|
---|
1042 | Word about Windows</a></h2>
|
---|
1043 | <p>Before we plunge into the myriad ncurses functions, let me clear
|
---|
1044 | few things about windows. Windows are explained in detail in
|
---|
1045 | following <a href="#WINDOWS">sections</a></p>
|
---|
1046 | <p>A Window is an imaginary screen defined by curses system. A
|
---|
1047 | window does not mean a bordered window which you usually see on
|
---|
1048 | Win9X platforms. When curses is initialized, it creates a default
|
---|
1049 | window named <var class="LITERAL">stdscr</var> which represents
|
---|
1050 | your 80x25 (or the size of window in which you are running) screen.
|
---|
1051 | If you are doing simple tasks like printing few strings, reading
|
---|
1052 | input etc., you can safely use this single window for all of your
|
---|
1053 | purposes. You can also create windows and call functions which
|
---|
1054 | explicitly work on the specified window.</p>
|
---|
1055 | <p>For example, if you call</p>
|
---|
1056 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
1057 | <tr>
|
---|
1058 | <td>
|
---|
1059 | <pre class="PROGRAMLISTING">
|
---|
1060 | <font color="#000000"> printw("Hi There !!!");
|
---|
1061 | refresh();</font>
|
---|
1062 | </pre></td>
|
---|
1063 | </tr>
|
---|
1064 | </table>
|
---|
1065 | <p>It prints the string on stdscr at the present cursor position.
|
---|
1066 | Similarly the call to refresh(), works on stdscr only.</p>
|
---|
1067 | <p>Say you have created <a href="#WINDOWS">windows</a> then you
|
---|
1068 | have to call a function with a 'w' added to the usual function.</p>
|
---|
1069 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
1070 | <tr>
|
---|
1071 | <td>
|
---|
1072 | <pre class="PROGRAMLISTING">
|
---|
1073 | <font color="#000000"> wprintw(win, "Hi There !!!");
|
---|
1074 | wrefresh(win);</font>
|
---|
1075 | </pre></td>
|
---|
1076 | </tr>
|
---|
1077 | </table>
|
---|
1078 | <p>As you will see in the rest of the document, naming of functions
|
---|
1079 | follow the same convention. For each function there usually are
|
---|
1080 | three more functions.</p>
|
---|
1081 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
1082 | <tr>
|
---|
1083 | <td>
|
---|
1084 | <pre class="PROGRAMLISTING">
|
---|
1085 | <font color=
|
---|
1086 | "#000000"> printw(string); /* Print on stdscr at present cursor position */
|
---|
1087 | mvprintw(y, x, string);/* Move to (y, x) then print string */
|
---|
1088 | wprintw(win, string); /* Print on window win at present cursor position */
|
---|
1089 | /* in the window */
|
---|
1090 | mvwprintw(win, y, x, string); /* Move to (y, x) relative to window */
|
---|
1091 | /* co-ordinates and then print */</font>
|
---|
1092 | </pre></td>
|
---|
1093 | </tr>
|
---|
1094 | </table>
|
---|
1095 | <p>Usually the w-less functions are macros which expand to
|
---|
1096 | corresponding w-function with stdscr as the window parameter.</p>
|
---|
1097 | </div>
|
---|
1098 | <div class="SECT1">
|
---|
1099 | <hr>
|
---|
1100 | <h2 class="SECT1"><a name="PRINTW" id="PRINTW">6. Output
|
---|
1101 | functions</a></h2>
|
---|
1102 | <p>I guess you can't wait any more to see some action. Back to our
|
---|
1103 | odyssey of curses functions. Now that curses is initialized, let's
|
---|
1104 | interact with world.</p>
|
---|
1105 | <p>There are three classes of functions which you can use to do
|
---|
1106 | output on screen.</p>
|
---|
1107 | <ol type="1">
|
---|
1108 | <li>
|
---|
1109 | <p>addch() class: Print single character with attributes</p>
|
---|
1110 | </li>
|
---|
1111 | <li>
|
---|
1112 | <p>printw() class: Print formatted output similar to printf()</p>
|
---|
1113 | </li>
|
---|
1114 | <li>
|
---|
1115 | <p>addstr() class: Print strings</p>
|
---|
1116 | </li>
|
---|
1117 | </ol>
|
---|
1118 | <p>These functions can be used interchangeably and it's a matter of
|
---|
1119 | style as to which class is used. Let's see each one in detail.</p>
|
---|
1120 | <div class="SECT2">
|
---|
1121 | <hr>
|
---|
1122 | <h3 class="SECT2"><a name="ADDCHCLASS" id="ADDCHCLASS">6.1. addch()
|
---|
1123 | class of functions</a></h3>
|
---|
1124 | <p>These functions put a single character into the current cursor
|
---|
1125 | location and advance the position of the cursor. You can give the
|
---|
1126 | character to be printed but they usually are used to print a
|
---|
1127 | character with some attributes. Attributes are explained in detail
|
---|
1128 | in later <a href="#ATTRIB">sections</a> of the document. If a
|
---|
1129 | character is associated with an attribute(bold, reverse video
|
---|
1130 | etc.), when curses prints the character, it is printed in that
|
---|
1131 | attribute.</p>
|
---|
1132 | <p>In order to combine a character with some attributes, you have
|
---|
1133 | two options:</p>
|
---|
1134 | <ul>
|
---|
1135 | <li>
|
---|
1136 | <p>By OR'ing a single character with the desired attribute macros.
|
---|
1137 | These attribute macros could be found in the header file
|
---|
1138 | <var class="LITERAL">ncurses.h</var>. For example, you want to
|
---|
1139 | print a character ch(of type char) bold and underlined, you would
|
---|
1140 | call addch() as below.</p>
|
---|
1141 | <table border="0" bgcolor="#E0E0E0" width="90%">
|
---|
1142 | <tr>
|
---|
1143 | <td>
|
---|
1144 | <pre class="PROGRAMLISTING">
|
---|
1145 | <font color="#000000"> addch(ch | A_BOLD | A_UNDERLINE);</font>
|
---|
1146 | </pre></td>
|
---|
1147 | </tr>
|
---|
1148 | </table>
|
---|
1149 | </li>
|
---|
1150 | <li>
|
---|
1151 | <p>By using functions like <var class=
|
---|
1152 | "LITERAL">attrset(),attron(),attroff()</var>. These functions are
|
---|
1153 | explained in the <a href="#ATTRIB">Attributes</a> section. Briefly,
|
---|
1154 | they manipulate the current attributes of the given window. Once
|
---|
1155 | set, the character printed in the window are associated with the
|
---|
1156 | attributes until it is turned off.</p>
|
---|
1157 | </li>
|
---|
1158 | </ul>
|
---|
1159 | <p>Additionally, <var class="LITERAL">curses</var> provides some
|
---|
1160 | special characters for character-based graphics. You can draw
|
---|
1161 | tables, horizontal or vertical lines, etc. You can find all
|
---|
1162 | avaliable characters in the header file <var class=
|
---|
1163 | "LITERAL">ncurses.h</var>. Try looking for macros beginning with
|
---|
1164 | <var class="LITERAL">ACS_</var> in this file.</p>
|
---|
1165 | </div>
|
---|
1166 | <div class="SECT2">
|
---|
1167 | <hr>
|
---|
1168 | <h3 class="SECT2"><a name="AEN298" id="AEN298">6.2. mvaddch(),
|
---|
1169 | waddch() and mvwaddch()</a></h3>
|
---|
1170 | <p><var class="LITERAL">mvaddch()</var> is used to move the cursor
|
---|
1171 | to a given point, and then print. Thus, the calls:</p>
|
---|
1172 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
1173 | <tr>
|
---|
1174 | <td>
|
---|
1175 | <pre class="PROGRAMLISTING">
|
---|
1176 | <font color=
|
---|
1177 | "#000000"> move(row,col); /* moves the cursor to row<em>th</em> row and col<em>th</em> column */
|
---|
1178 | addch(ch);</font>
|
---|
1179 | </pre></td>
|
---|
1180 | </tr>
|
---|
1181 | </table>
|
---|
1182 | can be replaced by
|
---|
1183 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
1184 | <tr>
|
---|
1185 | <td>
|
---|
1186 | <pre class="PROGRAMLISTING">
|
---|
1187 | <font color="#000000"> mvaddch(row,col,ch);</font>
|
---|
1188 | </pre></td>
|
---|
1189 | </tr>
|
---|
1190 | </table>
|
---|
1191 | <p><var class="LITERAL">waddch()</var> is similar to <var class=
|
---|
1192 | "LITERAL">addch()</var>, except that it adds a character into the
|
---|
1193 | given window. (Note that <var class="LITERAL">addch()</var> adds a
|
---|
1194 | character into the window <var class="LITERAL">stdscr</var>.)</p>
|
---|
1195 | <p>In a similar fashion <var class="LITERAL">mvwaddch()</var>
|
---|
1196 | function is used to add a character into the given window at the
|
---|
1197 | given coordinates.</p>
|
---|
1198 | <p>Now, we are familiar with the basic output function <var class=
|
---|
1199 | "LITERAL">addch()</var>. But, if we want to print a string, it
|
---|
1200 | would be very annoying to print it character by character.
|
---|
1201 | Fortunately, <var class="LITERAL">ncurses</var> provides
|
---|
1202 | <var class="LITERAL">printf</var><em>-like</em> or <var class=
|
---|
1203 | "LITERAL">puts</var><em>-like</em> functions.</p>
|
---|
1204 | </div>
|
---|
1205 | <div class="SECT2">
|
---|
1206 | <hr>
|
---|
1207 | <h3 class="SECT2"><a name="PRINTWCLASS" id="PRINTWCLASS">6.3.
|
---|
1208 | printw() class of functions</a></h3>
|
---|
1209 | <p>These functions are similar to <var class=
|
---|
1210 | "LITERAL">printf()</var> with the added capability of printing at
|
---|
1211 | any position on the screen.</p>
|
---|
1212 | <div class="SECT3">
|
---|
1213 | <hr>
|
---|
1214 | <h4 class="SECT3"><a name="PRINTWMVPRINTW" id=
|
---|
1215 | "PRINTWMVPRINTW">6.3.1. printw() and mvprintw</a></h4>
|
---|
1216 | <p>These two functions work much like <var class=
|
---|
1217 | "LITERAL">printf()</var>. <var class="LITERAL">mvprintw()</var> can
|
---|
1218 | be used to move the cursor to a position and then print. If you
|
---|
1219 | want to move the cursor first and then print using <var class=
|
---|
1220 | "LITERAL">printw()</var> function, use <var class=
|
---|
1221 | "LITERAL">move()</var> first and then use <var class=
|
---|
1222 | "LITERAL">printw()</var> though I see no point why one should avoid
|
---|
1223 | using <var class="LITERAL">mvprintw()</var>, you have the
|
---|
1224 | flexibility to manipulate.</p>
|
---|
1225 | </div>
|
---|
1226 | <div class="SECT3">
|
---|
1227 | <hr>
|
---|
1228 | <h4 class="SECT3"><a name="WPRINTWMVWPRINTW" id=
|
---|
1229 | "WPRINTWMVWPRINTW">6.3.2. wprintw() and mvwprintw</a></h4>
|
---|
1230 | <p>These two functions are similar to above two except that they
|
---|
1231 | print in the corresponding window given as argument.</p>
|
---|
1232 | </div>
|
---|
1233 | <div class="SECT3">
|
---|
1234 | <hr>
|
---|
1235 | <h4 class="SECT3"><a name="VWPRINTW" id="VWPRINTW">6.3.3.
|
---|
1236 | vwprintw()</a></h4>
|
---|
1237 | <p>This function is similar to <var class=
|
---|
1238 | "LITERAL">vprintf()</var>. This can be used when variable number of
|
---|
1239 | arguments are to be printed.</p>
|
---|
1240 | </div>
|
---|
1241 | <div class="SECT3">
|
---|
1242 | <hr>
|
---|
1243 | <h4 class="SECT3"><a name="SIMPLEPRINTWEX" id=
|
---|
1244 | "SIMPLEPRINTWEX">6.3.4. A Simple printw example</a></h4>
|
---|
1245 | <div class="EXAMPLE"><a name="BPREX" id="BPREX"></a>
|
---|
1246 | <p><b>Example 3. A Simple printw example</b></p>
|
---|
1247 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
1248 | <tr>
|
---|
1249 | <td>
|
---|
1250 | <pre class="PROGRAMLISTING">
|
---|
1251 | <font color="#000000"><span class=
|
---|
1252 | "INLINEMEDIAOBJECT">#include <ncurses.h> /* ncurses.h includes stdio.h */
|
---|
1253 | #include <string.h>
|
---|
1254 |
|
---|
1255 | int main()
|
---|
1256 | {
|
---|
1257 | char mesg[]="Just a string"; /* message to be appeared on the screen */
|
---|
1258 | int row,col; /* to store the number of rows and *
|
---|
1259 | * the number of colums of the screen */
|
---|
1260 | initscr(); /* start the curses mode */
|
---|
1261 | getmaxyx(stdscr,row,col); /* get the number of rows and columns */
|
---|
1262 | mvprintw(row/2,(col-strlen(mesg))/2,"%s",mesg);
|
---|
1263 | /* print the message at the center of the screen */
|
---|
1264 | mvprintw(row-2,0,"This screen has %d rows and %d columns\n",row,col);
|
---|
1265 | printw("Try resizing your window(if possible) and then run this program again");
|
---|
1266 | refresh();
|
---|
1267 | getch();
|
---|
1268 | endwin();
|
---|
1269 |
|
---|
1270 | return 0;
|
---|
1271 | }</span></font>
|
---|
1272 | </pre></td>
|
---|
1273 | </tr>
|
---|
1274 | </table>
|
---|
1275 | </div>
|
---|
1276 | <p>Above program demonstrates how easy it is to use <var class=
|
---|
1277 | "LITERAL">printw</var>. You just feed the coordinates and the
|
---|
1278 | message to be appeared on the screen, then it does what you
|
---|
1279 | want.</p>
|
---|
1280 | <p>The above program introduces us to a new function <var class=
|
---|
1281 | "LITERAL">getmaxyx()</var>, a macro defined in <var class=
|
---|
1282 | "LITERAL">ncurses.h</var>. It gives the number of columns and the
|
---|
1283 | number of rows in a given window. <var class=
|
---|
1284 | "LITERAL">getmaxyx()</var> does this by updating the variables
|
---|
1285 | given to it. Since <var class="LITERAL">getmaxyx()</var> is not a
|
---|
1286 | function we don't pass pointers to it, we just give two integer
|
---|
1287 | variables.</p>
|
---|
1288 | </div>
|
---|
1289 | </div>
|
---|
1290 | <div class="SECT2">
|
---|
1291 | <hr>
|
---|
1292 | <h3 class="SECT2"><a name="ADDSTRCLASS" id="ADDSTRCLASS">6.4.
|
---|
1293 | addstr() class of functions</a></h3>
|
---|
1294 | <p><var class="LITERAL">addstr()</var> is used to put a character
|
---|
1295 | string into a given window. This function is similar to calling
|
---|
1296 | <var class="LITERAL">addch()</var> once for each character in a
|
---|
1297 | given string. This is true for all output functions. There are
|
---|
1298 | other functions from this family such as <var class=
|
---|
1299 | "LITERAL">mvaddstr(),mvwaddstr()</var> and <var class=
|
---|
1300 | "LITERAL">waddstr()</var>, which obey the naming convention of
|
---|
1301 | curses.(e.g. mvaddstr() is similar to the respective calls move()
|
---|
1302 | and then addstr().) Another function of this family is addnstr(),
|
---|
1303 | which takes an integer parameter(say n) additionally. This function
|
---|
1304 | puts at most n characters into the screen. If n is negative, then
|
---|
1305 | the entire string will be added.</p>
|
---|
1306 | </div>
|
---|
1307 | <div class="SECT2">
|
---|
1308 | <hr>
|
---|
1309 | <h3 class="SECT2"><a name="ACAUTION" id="ACAUTION">6.5. A word of
|
---|
1310 | caution</a></h3>
|
---|
1311 | <p>All these functions take y co-ordinate first and then x in their
|
---|
1312 | arguments. A common mistake by beginners is to pass x,y in that
|
---|
1313 | order. If you are doing too many manipulations of (y,x)
|
---|
1314 | co-ordinates, think of dividing the screen into windows and
|
---|
1315 | manipulate each one separately. Windows are explained in the
|
---|
1316 | <a href="#WINDOWS">windows</a> section.</p>
|
---|
1317 | </div>
|
---|
1318 | </div>
|
---|
1319 | <div class="SECT1">
|
---|
1320 | <hr>
|
---|
1321 | <h2 class="SECT1"><a name="SCANW" id="SCANW">7. Input
|
---|
1322 | functions</a></h2>
|
---|
1323 | <p>Well, printing without taking input, is boring. Let's see
|
---|
1324 | functions which allow us to get input from user. These functions
|
---|
1325 | also can be divided into three categories.</p>
|
---|
1326 | <ol type="1">
|
---|
1327 | <li>
|
---|
1328 | <p>getch() class: Get a character</p>
|
---|
1329 | </li>
|
---|
1330 | <li>
|
---|
1331 | <p>scanw() class: Get formatted input</p>
|
---|
1332 | </li>
|
---|
1333 | <li>
|
---|
1334 | <p>getstr() class: Get strings</p>
|
---|
1335 | </li>
|
---|
1336 | </ol>
|
---|
1337 | <div class="SECT2">
|
---|
1338 | <hr>
|
---|
1339 | <h3 class="SECT2"><a name="GETCHCLASS" id="GETCHCLASS">7.1. getch()
|
---|
1340 | class of functions</a></h3>
|
---|
1341 | <p>These functions read a single character from the terminal. But
|
---|
1342 | there are several subtle facts to consider. For example if you
|
---|
1343 | don't use the function cbreak(), curses will not read your input
|
---|
1344 | characters contiguously but will begin read them only after a new
|
---|
1345 | line or an EOF is encountered. In order to avoid this, the cbreak()
|
---|
1346 | function must used so that characters are immediately available to
|
---|
1347 | your program. Another widely used function is noecho(). As the name
|
---|
1348 | suggests, when this function is set (used), the characters that are
|
---|
1349 | keyed in by the user will not show up on the screen. The two
|
---|
1350 | functions cbreak() and noecho() are typical examples of key
|
---|
1351 | management. Functions of this genre are explained in the <a href=
|
---|
1352 | "#KEYS">key management section</a> .</p>
|
---|
1353 | </div>
|
---|
1354 | <div class="SECT2">
|
---|
1355 | <hr>
|
---|
1356 | <h3 class="SECT2"><a name="SCANWCLASS" id="SCANWCLASS">7.2. scanw()
|
---|
1357 | class of functions</a></h3>
|
---|
1358 | <p>These functions are similar to <var class=
|
---|
1359 | "LITERAL">scanf()</var> with the added capability of getting the
|
---|
1360 | input from any location on the screen.</p>
|
---|
1361 | <div class="SECT3">
|
---|
1362 | <hr>
|
---|
1363 | <h4 class="SECT3"><a name="SCANWMVSCANW" id="SCANWMVSCANW">7.2.1.
|
---|
1364 | scanw() and mvscanw</a></h4>
|
---|
1365 | <p>The usage of these functions is similar to that of <var class=
|
---|
1366 | "LITERAL">sscanf()</var>, where the line to be scanned is provided
|
---|
1367 | by <var class="LITERAL">wgetstr()</var> function. That is, these
|
---|
1368 | functions call to <var class="LITERAL">wgetstr()</var>
|
---|
1369 | function(explained below) and uses the resulting line for a
|
---|
1370 | scan.</p>
|
---|
1371 | </div>
|
---|
1372 | <div class="SECT3">
|
---|
1373 | <hr>
|
---|
1374 | <h4 class="SECT3"><a name="WSCANWMVWSCANW" id=
|
---|
1375 | "WSCANWMVWSCANW">7.2.2. wscanw() and mvwscanw()</a></h4>
|
---|
1376 | <p>These are similar to above two functions except that they read
|
---|
1377 | from a window, which is supplied as one of the arguments to these
|
---|
1378 | functions.</p>
|
---|
1379 | </div>
|
---|
1380 | <div class="SECT3">
|
---|
1381 | <hr>
|
---|
1382 | <h4 class="SECT3"><a name="VWSCANW" id="VWSCANW">7.2.3.
|
---|
1383 | vwscanw()</a></h4>
|
---|
1384 | <p>This function is similar to <var class="LITERAL">vscanf()</var>.
|
---|
1385 | This can be used when a variable number of arguments are to be
|
---|
1386 | scanned.</p>
|
---|
1387 | </div>
|
---|
1388 | </div>
|
---|
1389 | <div class="SECT2">
|
---|
1390 | <hr>
|
---|
1391 | <h3 class="SECT2"><a name="GETSTRCLASS" id="GETSTRCLASS">7.3.
|
---|
1392 | getstr() class of functions</a></h3>
|
---|
1393 | <p>These functions are used to get strings from the terminal. In
|
---|
1394 | essence, this function performs the same task as would be achieved
|
---|
1395 | by a series of calls to <var class="LITERAL">getch()</var> until a
|
---|
1396 | newline, carriage return, or end-of-file is received. The resulting
|
---|
1397 | string of characters are pointed to by <var class=
|
---|
1398 | "LITERAL">str</var>, which is a character pointer provided by the
|
---|
1399 | user.</p>
|
---|
1400 | </div>
|
---|
1401 | <div class="SECT2">
|
---|
1402 | <hr>
|
---|
1403 | <h3 class="SECT2"><a name="GETSTREX" id="GETSTREX">7.4. Some
|
---|
1404 | examples</a></h3>
|
---|
1405 | <div class="EXAMPLE"><a name="BSCEX" id="BSCEX"></a>
|
---|
1406 | <p><b>Example 4. A Simple scanw example</b></p>
|
---|
1407 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
1408 | <tr>
|
---|
1409 | <td>
|
---|
1410 | <pre class="PROGRAMLISTING">
|
---|
1411 | <font color="#000000"><span class=
|
---|
1412 | "INLINEMEDIAOBJECT">#include <ncurses.h> /* ncurses.h includes stdio.h */
|
---|
1413 | #include <string.h>
|
---|
1414 |
|
---|
1415 | int main()
|
---|
1416 | {
|
---|
1417 | char mesg[]="Enter a string: "; /* message to be appeared on the screen */
|
---|
1418 | char str[80];
|
---|
1419 | int row,col; /* to store the number of rows and *
|
---|
1420 | * the number of colums of the screen */
|
---|
1421 | initscr(); /* start the curses mode */
|
---|
1422 | getmaxyx(stdscr,row,col); /* get the number of rows and columns */
|
---|
1423 | mvprintw(row/2,(col-strlen(mesg))/2,"%s",mesg);
|
---|
1424 | /* print the message at the center of the screen */
|
---|
1425 | getstr(str);
|
---|
1426 | mvprintw(LINES - 2, 0, "You Entered: %s", str);
|
---|
1427 | getch();
|
---|
1428 | endwin();
|
---|
1429 |
|
---|
1430 | return 0;
|
---|
1431 | }</span></font>
|
---|
1432 | </pre></td>
|
---|
1433 | </tr>
|
---|
1434 | </table>
|
---|
1435 | </div>
|
---|
1436 | </div>
|
---|
1437 | </div>
|
---|
1438 | <div class="SECT1">
|
---|
1439 | <hr>
|
---|
1440 | <h2 class="SECT1"><a name="ATTRIB" id="ATTRIB">8.
|
---|
1441 | Attributes</a></h2>
|
---|
1442 | <p>We have seen an example of how attributes can be used to print
|
---|
1443 | characters with some special effects. Attributes, when set
|
---|
1444 | prudently, can present information in an easy, understandable
|
---|
1445 | manner. The following program takes a C file as input and prints
|
---|
1446 | the file with comments in bold. Scan through the code.</p>
|
---|
1447 | <div class="EXAMPLE"><a name="BSIAT" id="BSIAT"></a>
|
---|
1448 | <p><b>Example 5. A Simple Attributes example</b></p>
|
---|
1449 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
1450 | <tr>
|
---|
1451 | <td>
|
---|
1452 | <pre class="PROGRAMLISTING">
|
---|
1453 | <font color="#000000"><span class=
|
---|
1454 | "INLINEMEDIAOBJECT">/* pager functionality by Joseph Spainhour" <spainhou@bellsouth.net> */
|
---|
1455 | #include <ncurses.h>
|
---|
1456 | #include <stdlib.h>
|
---|
1457 |
|
---|
1458 | int main(int argc, char *argv[])
|
---|
1459 | {
|
---|
1460 | int ch, prev, row, col;
|
---|
1461 | prev = EOF;
|
---|
1462 | FILE *fp;
|
---|
1463 | int y, x;
|
---|
1464 |
|
---|
1465 | if(argc != 2)
|
---|
1466 | {
|
---|
1467 | printf("Usage: %s <a c file name>\n", argv[0]);
|
---|
1468 | exit(1);
|
---|
1469 | }
|
---|
1470 | fp = fopen(argv[1], "r");
|
---|
1471 | if(fp == NULL)
|
---|
1472 | {
|
---|
1473 | perror("Cannot open input file");
|
---|
1474 | exit(1);
|
---|
1475 | }
|
---|
1476 | initscr(); /* Start curses mode */
|
---|
1477 | getmaxyx(stdscr, row, col); /* find the boundaries of the screeen */
|
---|
1478 | while((ch = fgetc(fp)) != EOF) /* read the file till we reach the end */
|
---|
1479 | {
|
---|
1480 | getyx(stdscr, y, x); /* get the current curser position */
|
---|
1481 | if(y == (row - 1)) /* are we are at the end of the screen */
|
---|
1482 | {
|
---|
1483 | printw("<-Press Any Key->"); /* tell the user to press a key */
|
---|
1484 | getch();
|
---|
1485 | clear(); /* clear the screen */
|
---|
1486 | move(0, 0); /* start at the beginning of the screen */
|
---|
1487 | }
|
---|
1488 | if(prev == '/' && ch == '*') /* If it is / and * then only
|
---|
1489 | * switch bold on */
|
---|
1490 | {
|
---|
1491 | attron(A_BOLD); /* cut bold on */
|
---|
1492 | getyx(stdscr, y, x); /* get the current curser position */
|
---|
1493 | move(y, x - 1); /* back up one space */
|
---|
1494 | printw("%c%c", '/', ch); /* The actual printing is done here */
|
---|
1495 | }
|
---|
1496 | else
|
---|
1497 | printw("%c", ch);
|
---|
1498 | refresh();
|
---|
1499 | if(prev == '*' && ch == '/')
|
---|
1500 | attroff(A_BOLD); /* Switch it off once we got *
|
---|
1501 | * and then / */
|
---|
1502 | prev = ch;
|
---|
1503 | }
|
---|
1504 | endwin(); /* End curses mode */
|
---|
1505 | fclose(fp);
|
---|
1506 | return 0;
|
---|
1507 | }</span></font>
|
---|
1508 | </pre></td>
|
---|
1509 | </tr>
|
---|
1510 | </table>
|
---|
1511 | </div>
|
---|
1512 | <p>Don't worry about all those initialization and other crap.
|
---|
1513 | Concentrate on the while loop. It reads each character in the file
|
---|
1514 | and searches for the pattern /*. Once it spots the pattern, it
|
---|
1515 | switches the BOLD attribute on with <var class=
|
---|
1516 | "LITERAL">attron()</var> . When we get the pattern */ it is
|
---|
1517 | switched off by <var class="LITERAL">attroff()</var> .</p>
|
---|
1518 | <p>The above program also introduces us to two useful functions
|
---|
1519 | <var class="LITERAL">getyx()</var> and <var class=
|
---|
1520 | "LITERAL">move()</var>. The first function gets the co-ordinates of
|
---|
1521 | the present cursor into the variables y, x. Since getyx() is a
|
---|
1522 | macro we don't have to pass pointers to variables. The function
|
---|
1523 | <var class="LITERAL">move()</var> moves the cursor to the
|
---|
1524 | co-ordinates given to it.</p>
|
---|
1525 | <p>The above program is really a simple one which doesn't do much.
|
---|
1526 | On these lines one could write a more useful program which reads a
|
---|
1527 | C file, parses it and prints it in different colors. One could even
|
---|
1528 | extend it to other languages as well.</p>
|
---|
1529 | <div class="SECT2">
|
---|
1530 | <hr>
|
---|
1531 | <h3 class="SECT2"><a name="ATTRIBDETAILS" id="ATTRIBDETAILS">8.1.
|
---|
1532 | The details</a></h3>
|
---|
1533 | <p>Let's get into more details of attributes. The functions
|
---|
1534 | <var class="LITERAL">attron(), attroff(), attrset()</var> , and
|
---|
1535 | their sister functions <var class="LITERAL">attr_get()</var> etc..
|
---|
1536 | can be used to switch attributes on/off , get attributes and
|
---|
1537 | produce a colorful display.</p>
|
---|
1538 | <p>The functions attron and attroff take a bit-mask of attributes
|
---|
1539 | and switch them on or off, respectively. The following video
|
---|
1540 | attributes, which are defined in <curses.h> can be passed to
|
---|
1541 | these functions.</p>
|
---|
1542 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
1543 | <tr>
|
---|
1544 | <td>
|
---|
1545 | <pre class="PROGRAMLISTING">
|
---|
1546 | <font color="#000000">
|
---|
1547 | A_NORMAL Normal display (no highlight)
|
---|
1548 | A_STANDOUT Best highlighting mode of the terminal.
|
---|
1549 | A_UNDERLINE Underlining
|
---|
1550 | A_REVERSE Reverse video
|
---|
1551 | A_BLINK Blinking
|
---|
1552 | A_DIM Half bright
|
---|
1553 | A_BOLD Extra bright or bold
|
---|
1554 | A_PROTECT Protected mode
|
---|
1555 | A_INVIS Invisible or blank mode
|
---|
1556 | A_ALTCHARSET Alternate character set
|
---|
1557 | A_CHARTEXT Bit-mask to extract a character
|
---|
1558 | COLOR_PAIR(n) Color-pair number n
|
---|
1559 | </font>
|
---|
1560 | </pre></td>
|
---|
1561 | </tr>
|
---|
1562 | </table>
|
---|
1563 | <p>The last one is the most colorful one :-) Colors are explained
|
---|
1564 | in the <a href="#color" target="_top">next sections</a>.</p>
|
---|
1565 | <p>We can OR(|) any number of above attributes to get a combined
|
---|
1566 | effect. If you wanted reverse video with blinking characters you
|
---|
1567 | can use</p>
|
---|
1568 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
1569 | <tr>
|
---|
1570 | <td>
|
---|
1571 | <pre class="PROGRAMLISTING">
|
---|
1572 | <font color="#000000"> attron(A_REVERSE | A_BLINK);</font>
|
---|
1573 | </pre></td>
|
---|
1574 | </tr>
|
---|
1575 | </table>
|
---|
1576 | </div>
|
---|
1577 | <div class="SECT2">
|
---|
1578 | <hr>
|
---|
1579 | <h3 class="SECT2"><a name="ATTRONVSATTRSET" id=
|
---|
1580 | "ATTRONVSATTRSET">8.2. attron() vs attrset()</a></h3>
|
---|
1581 | <p>Then what is the difference between attron() and attrset()?
|
---|
1582 | attrset sets the attributes of window whereas attron just switches
|
---|
1583 | on the attribute given to it. So attrset() fully overrides whatever
|
---|
1584 | attributes the window previously had and sets it to the new
|
---|
1585 | attribute(s). Similarly attroff() just switches off the
|
---|
1586 | attribute(s) given to it as an argument. This gives us the
|
---|
1587 | flexibility of managing attributes easily.But if you use them
|
---|
1588 | carelessly you may loose track of what attributes the window has
|
---|
1589 | and garble the display. This is especially true while managing
|
---|
1590 | menus with colors and highlighting. So decide on a consistent
|
---|
1591 | policy and stick to it. You can always use <var class=
|
---|
1592 | "LITERAL">standend()</var> which is equivalent to <var class=
|
---|
1593 | "LITERAL">attrset(A_NORMAL)</var> which turns off all attributes
|
---|
1594 | and brings you to normal mode.</p>
|
---|
1595 | </div>
|
---|
1596 | <div class="SECT2">
|
---|
1597 | <hr>
|
---|
1598 | <h3 class="SECT2"><a name="ATTR_GET" id="ATTR_GET">8.3.
|
---|
1599 | attr_get()</a></h3>
|
---|
1600 | <p>The function attr_get() gets the current attributes and color
|
---|
1601 | pair of the window. Though we might not use this as often as the
|
---|
1602 | above functions, this is useful in scanning areas of screen. Say we
|
---|
1603 | wanted to do some complex update on screen and we are not sure what
|
---|
1604 | attribute each character is associated with. Then this function can
|
---|
1605 | be used with either attrset or attron to produce the desired
|
---|
1606 | effect.</p>
|
---|
1607 | </div>
|
---|
1608 | <div class="SECT2">
|
---|
1609 | <hr>
|
---|
1610 | <h3 class="SECT2"><a name="ATTR_FUNCS" id="ATTR_FUNCS">8.4. attr_
|
---|
1611 | functions</a></h3>
|
---|
1612 | <p>There are series of functions like attr_set(), attr_on etc..
|
---|
1613 | These are similar to above functions except that they take
|
---|
1614 | parameters of type <var class="LITERAL">attr_t</var>.</p>
|
---|
1615 | </div>
|
---|
1616 | <div class="SECT2">
|
---|
1617 | <hr>
|
---|
1618 | <h3 class="SECT2"><a name="WATTRFUNCS" id="WATTRFUNCS">8.5. wattr
|
---|
1619 | functions</a></h3>
|
---|
1620 | <p>For each of the above functions we have a corresponding function
|
---|
1621 | with 'w' which operates on a particular window. The above functions
|
---|
1622 | operate on stdscr.</p>
|
---|
1623 | </div>
|
---|
1624 | <div class="SECT2">
|
---|
1625 | <hr>
|
---|
1626 | <h3 class="SECT2"><a name="CHGAT" id="CHGAT">8.6. chgat()
|
---|
1627 | functions</a></h3>
|
---|
1628 | <p>The function chgat() is listed in the end of the man page
|
---|
1629 | curs_attr. It actually is a useful one. This function can be used
|
---|
1630 | to set attributes for a group of characters without moving. I mean
|
---|
1631 | it !!! without moving the cursor :-) It changes the attributes of a
|
---|
1632 | given number of characters starting at the current cursor
|
---|
1633 | location.</p>
|
---|
1634 | <p>We can give -1 as the character count to update till end of
|
---|
1635 | line. If you want to change attributes of characters from current
|
---|
1636 | position to end of line, just use this.</p>
|
---|
1637 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
1638 | <tr>
|
---|
1639 | <td>
|
---|
1640 | <pre class="PROGRAMLISTING">
|
---|
1641 | <font color="#000000"> chgat(-1, A_REVERSE, 0, NULL);</font>
|
---|
1642 | </pre></td>
|
---|
1643 | </tr>
|
---|
1644 | </table>
|
---|
1645 | <p>This function is useful when changing attributes for characters
|
---|
1646 | that are already on the screen. Move to the character from which
|
---|
1647 | you want to change and change the attribute.</p>
|
---|
1648 | <p>Other functions wchgat(), mvchgat(), wchgat() behave similarly
|
---|
1649 | except that the w functions operate on the particular window. The
|
---|
1650 | mv functions first move the cursor then perform the work given to
|
---|
1651 | them. Actually chgat is a macro which is replaced by a wchgat()
|
---|
1652 | with stdscr as the window. Most of the "w-less" functions are
|
---|
1653 | macros.</p>
|
---|
1654 | <div class="EXAMPLE"><a name="BWICH" id="BWICH"></a>
|
---|
1655 | <p><b>Example 6. Chgat() Usage example</b></p>
|
---|
1656 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
1657 | <tr>
|
---|
1658 | <td>
|
---|
1659 | <pre class="PROGRAMLISTING">
|
---|
1660 | <font color="#000000"><span class=
|
---|
1661 | "INLINEMEDIAOBJECT">#include <ncurses.h>
|
---|
1662 |
|
---|
1663 | int main(int argc, char *argv[])
|
---|
1664 | { initscr(); /* Start curses mode */
|
---|
1665 | start_color(); /* Start color functionality */
|
---|
1666 |
|
---|
1667 | init_pair(1, COLOR_CYAN, COLOR_BLACK);
|
---|
1668 | printw("A Big string which i didn't care to type fully ");
|
---|
1669 | mvchgat(0, 0, -1, A_BLINK, 1, NULL);
|
---|
1670 | /*
|
---|
1671 | * First two parameters specify the position at which to start
|
---|
1672 | * Third parameter number of characters to update. -1 means till
|
---|
1673 | * end of line
|
---|
1674 | * Forth parameter is the normal attribute you wanted to give
|
---|
1675 | * to the charcter
|
---|
1676 | * Fifth is the color index. It is the index given during init_pair()
|
---|
1677 | * use 0 if you didn't want color
|
---|
1678 | * Sixth one is always NULL
|
---|
1679 | */
|
---|
1680 | refresh();
|
---|
1681 | getch();
|
---|
1682 | endwin(); /* End curses mode */
|
---|
1683 | return 0;
|
---|
1684 | }</span></font>
|
---|
1685 | </pre></td>
|
---|
1686 | </tr>
|
---|
1687 | </table>
|
---|
1688 | </div>
|
---|
1689 | <p>This example also introduces us to the color world of curses.
|
---|
1690 | Colors will be explained in detail later. Use 0 for no color.</p>
|
---|
1691 | </div>
|
---|
1692 | </div>
|
---|
1693 | <div class="SECT1">
|
---|
1694 | <hr>
|
---|
1695 | <h2 class="SECT1"><a name="WINDOWS" id="WINDOWS">9.
|
---|
1696 | Windows</a></h2>
|
---|
1697 | <p>Windows form the most important concept in curses. You have seen
|
---|
1698 | the standard window stdscr above where all the functions implicitly
|
---|
1699 | operated on this window. Now to make design even a simplest GUI,
|
---|
1700 | you need to resort to windows. The main reason you may want to use
|
---|
1701 | windows is to manipulate parts of the screen separately, for better
|
---|
1702 | efficiency, by updating only the windows that need to be changed
|
---|
1703 | and for a better design. I would say the last reason is the most
|
---|
1704 | important in going for windows. You should always strive for a
|
---|
1705 | better and easy-to-manage design in your programs. If you are
|
---|
1706 | writing big, complex GUIs this is of pivotal importance before you
|
---|
1707 | start doing anything.</p>
|
---|
1708 | <div class="SECT2">
|
---|
1709 | <hr>
|
---|
1710 | <h3 class="SECT2"><a name="WINDOWBASICS" id="WINDOWBASICS">9.1. The
|
---|
1711 | basics</a></h3>
|
---|
1712 | <p>A Window can be created by calling the function <var class=
|
---|
1713 | "LITERAL">newwin()</var>. It doesn't create any thing on the screen
|
---|
1714 | actually. It allocates memory for a structure to manipulate the
|
---|
1715 | window and updates the structure with data regarding the window
|
---|
1716 | like it's size, beginy, beginx etc.. Hence in curses, a window is
|
---|
1717 | just an abstraction of an imaginary window, which can be
|
---|
1718 | manipulated independent of other parts of screen. The function
|
---|
1719 | newwin() returns a pointer to structure WINDOW, which can be passed
|
---|
1720 | to window related functions like wprintw() etc.. Finally the window
|
---|
1721 | can be destroyed with delwin(). It will deallocate the memory
|
---|
1722 | associated with the window structure.</p>
|
---|
1723 | </div>
|
---|
1724 | <div class="SECT2">
|
---|
1725 | <hr>
|
---|
1726 | <h3 class="SECT2"><a name="LETBEWINDOW" id="LETBEWINDOW">9.2. Let
|
---|
1727 | there be a Window !!!</a></h3>
|
---|
1728 | <p>What fun is it, if a window is created and we can't see it. So
|
---|
1729 | the fun part begins by displaying the window. The function
|
---|
1730 | <var class="LITERAL">box()</var> can be used to draw a border
|
---|
1731 | around the window. Let's explore these functions in more detail in
|
---|
1732 | this example.</p>
|
---|
1733 | <div class="EXAMPLE"><a name="BWIBO" id="BWIBO"></a>
|
---|
1734 | <p><b>Example 7. Window Border example</b></p>
|
---|
1735 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
1736 | <tr>
|
---|
1737 | <td>
|
---|
1738 | <pre class="PROGRAMLISTING">
|
---|
1739 | <font color="#000000"><span class=
|
---|
1740 | "INLINEMEDIAOBJECT">#include <ncurses.h>
|
---|
1741 |
|
---|
1742 |
|
---|
1743 | WINDOW *create_newwin(int height, int width, int starty, int startx);
|
---|
1744 | void destroy_win(WINDOW *local_win);
|
---|
1745 |
|
---|
1746 | int main(int argc, char *argv[])
|
---|
1747 | { WINDOW *my_win;
|
---|
1748 | int startx, starty, width, height;
|
---|
1749 | int ch;
|
---|
1750 |
|
---|
1751 | initscr(); /* Start curses mode */
|
---|
1752 | cbreak(); /* Line buffering disabled, Pass on
|
---|
1753 | * everty thing to me */
|
---|
1754 | keypad(stdscr, TRUE); /* I need that nifty F1 */
|
---|
1755 |
|
---|
1756 | height = 3;
|
---|
1757 | width = 10;
|
---|
1758 | starty = (LINES - height) / 2; /* Calculating for a center placement */
|
---|
1759 | startx = (COLS - width) / 2; /* of the window */
|
---|
1760 | printw("Press F1 to exit");
|
---|
1761 | refresh();
|
---|
1762 | my_win = create_newwin(height, width, starty, startx);
|
---|
1763 |
|
---|
1764 | while((ch = getch()) != KEY_F(1))
|
---|
1765 | { switch(ch)
|
---|
1766 | { case KEY_LEFT:
|
---|
1767 | destroy_win(my_win);
|
---|
1768 | my_win = create_newwin(height, width, starty,--startx);
|
---|
1769 | break;
|
---|
1770 | case KEY_RIGHT:
|
---|
1771 | destroy_win(my_win);
|
---|
1772 | my_win = create_newwin(height, width, starty,++startx);
|
---|
1773 | break;
|
---|
1774 | case KEY_UP:
|
---|
1775 | destroy_win(my_win);
|
---|
1776 | my_win = create_newwin(height, width, --starty,startx);
|
---|
1777 | break;
|
---|
1778 | case KEY_DOWN:
|
---|
1779 | destroy_win(my_win);
|
---|
1780 | my_win = create_newwin(height, width, ++starty,startx);
|
---|
1781 | break;
|
---|
1782 | }
|
---|
1783 | }
|
---|
1784 |
|
---|
1785 | endwin(); /* End curses mode */
|
---|
1786 | return 0;
|
---|
1787 | }
|
---|
1788 |
|
---|
1789 | WINDOW *create_newwin(int height, int width, int starty, int startx)
|
---|
1790 | { WINDOW *local_win;
|
---|
1791 |
|
---|
1792 | local_win = newwin(height, width, starty, startx);
|
---|
1793 | box(local_win, 0 , 0); /* 0, 0 gives default characters
|
---|
1794 | * for the vertical and horizontal
|
---|
1795 | * lines */
|
---|
1796 | wrefresh(local_win); /* Show that box */
|
---|
1797 |
|
---|
1798 | return local_win;
|
---|
1799 | }
|
---|
1800 |
|
---|
1801 | void destroy_win(WINDOW *local_win)
|
---|
1802 | {
|
---|
1803 | /* box(local_win, ' ', ' '); : This won't produce the desired
|
---|
1804 | * result of erasing the window. It will leave it's four corners
|
---|
1805 | * and so an ugly remnant of window.
|
---|
1806 | */
|
---|
1807 | wborder(local_win, ' ', ' ', ' ',' ',' ',' ',' ',' ');
|
---|
1808 | /* The parameters taken are
|
---|
1809 | * 1. win: the window on which to operate
|
---|
1810 | * 2. ls: character to be used for the left side of the window
|
---|
1811 | * 3. rs: character to be used for the right side of the window
|
---|
1812 | * 4. ts: character to be used for the top side of the window
|
---|
1813 | * 5. bs: character to be used for the bottom side of the window
|
---|
1814 | * 6. tl: character to be used for the top left corner of the window
|
---|
1815 | * 7. tr: character to be used for the top right corner of the window
|
---|
1816 | * 8. bl: character to be used for the bottom left corner of the window
|
---|
1817 | * 9. br: character to be used for the bottom right corner of the window
|
---|
1818 | */
|
---|
1819 | wrefresh(local_win);
|
---|
1820 | delwin(local_win);
|
---|
1821 | }</span></font>
|
---|
1822 | </pre></td>
|
---|
1823 | </tr>
|
---|
1824 | </table>
|
---|
1825 | </div>
|
---|
1826 | </div>
|
---|
1827 | <div class="SECT2">
|
---|
1828 | <hr>
|
---|
1829 | <h3 class="SECT2"><a name="BORDEREXEXPL" id="BORDEREXEXPL">9.3.
|
---|
1830 | Explanation</a></h3>
|
---|
1831 | <p>Don't scream. I know it's a big example. But I have to explain
|
---|
1832 | some important things here :-). This program creates a rectangular
|
---|
1833 | window that can be moved with left, right, up, down arrow keys. It
|
---|
1834 | repeatedly creates and destroys windows as user press a key. Don't
|
---|
1835 | go beyond the screen limits. Checking for those limits is left as
|
---|
1836 | an exercise for the reader. Let's dissect it by line by line.</p>
|
---|
1837 | <p>The <var class="LITERAL">create_newwin()</var> function creates
|
---|
1838 | a window with <var class="LITERAL">newwin()</var> and displays a
|
---|
1839 | border around it with box. The function <var class=
|
---|
1840 | "LITERAL">destroy_win()</var> first erases the window from screen
|
---|
1841 | by painting a border with ' ' character and then calling
|
---|
1842 | <var class="LITERAL">delwin()</var> to deallocate memory related to
|
---|
1843 | it. Depending on the key the user presses, starty or startx is
|
---|
1844 | changed and a new window is created.</p>
|
---|
1845 | <p>In the destroy_win, as you can see, I used wborder instead of
|
---|
1846 | box. The reason is written in the comments (You missed it. I know.
|
---|
1847 | Read the code :-)). wborder draws a border around the window with
|
---|
1848 | the characters given to it as the 4 corner points and the 4 lines.
|
---|
1849 | To put it clearly, if you have called wborder as below:</p>
|
---|
1850 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
1851 | <tr>
|
---|
1852 | <td>
|
---|
1853 | <pre class="PROGRAMLISTING">
|
---|
1854 | <font color=
|
---|
1855 | "#000000"> wborder(win, '|', '|', '-', '-', '+', '+', '+', '+');</font>
|
---|
1856 | </pre></td>
|
---|
1857 | </tr>
|
---|
1858 | </table>
|
---|
1859 | <p>it produces some thing like</p>
|
---|
1860 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
1861 | <tr>
|
---|
1862 | <td>
|
---|
1863 | <pre class="PROGRAMLISTING">
|
---|
1864 | <font color="#000000"> +------------+
|
---|
1865 | | |
|
---|
1866 | | |
|
---|
1867 | | |
|
---|
1868 | | |
|
---|
1869 | | |
|
---|
1870 | | |
|
---|
1871 | +------------+</font>
|
---|
1872 | </pre></td>
|
---|
1873 | </tr>
|
---|
1874 | </table>
|
---|
1875 | </div>
|
---|
1876 | <div class="SECT2">
|
---|
1877 | <hr>
|
---|
1878 | <h3 class="SECT2"><a name="OTHERSTUFF" id="OTHERSTUFF">9.4. The
|
---|
1879 | other stuff in the example</a></h3>
|
---|
1880 | <p>You can also see in the above examples, that I have used the
|
---|
1881 | variables COLS, LINES which are initialized to the screen sizes
|
---|
1882 | after initscr(). They can be useful in finding screen dimensions
|
---|
1883 | and finding the center co-ordinate of the screen as above. The
|
---|
1884 | function <var class="LITERAL">getch()</var> as usual gets the key
|
---|
1885 | from keyboard and according to the key it does the corresponding
|
---|
1886 | work. This type of switch- case is very common in any GUI based
|
---|
1887 | programs.</p>
|
---|
1888 | </div>
|
---|
1889 | <div class="SECT2">
|
---|
1890 | <hr>
|
---|
1891 | <h3 class="SECT2"><a name="OTHERBORDERFUNCS" id=
|
---|
1892 | "OTHERBORDERFUNCS">9.5. Other Border functions</a></h3>
|
---|
1893 | <p>Above program is grossly inefficient in that with each press of
|
---|
1894 | a key, a window is destroyed and another is created. So let's write
|
---|
1895 | a more efficient program which uses other border related
|
---|
1896 | functions.</p>
|
---|
1897 | <p>The following program uses <var class="LITERAL">mvhline()</var>
|
---|
1898 | and <var class="LITERAL">mvvline()</var> to achieve similar effect.
|
---|
1899 | These two functions are simple. They create a horizontal or
|
---|
1900 | vertical line of the specified length at the specified
|
---|
1901 | position.</p>
|
---|
1902 | <div class="EXAMPLE"><a name="BOTBO" id="BOTBO"></a>
|
---|
1903 | <p><b>Example 8. More border functions</b></p>
|
---|
1904 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
1905 | <tr>
|
---|
1906 | <td>
|
---|
1907 | <pre class="PROGRAMLISTING">
|
---|
1908 | <font color="#000000"><span class=
|
---|
1909 | "INLINEMEDIAOBJECT">#include <ncurses.h>
|
---|
1910 |
|
---|
1911 | typedef struct _win_border_struct {
|
---|
1912 | chtype ls, rs, ts, bs,
|
---|
1913 | tl, tr, bl, br;
|
---|
1914 | }WIN_BORDER;
|
---|
1915 |
|
---|
1916 | typedef struct _WIN_struct {
|
---|
1917 |
|
---|
1918 | int startx, starty;
|
---|
1919 | int height, width;
|
---|
1920 | WIN_BORDER border;
|
---|
1921 | }WIN;
|
---|
1922 |
|
---|
1923 | void init_win_params(WIN *p_win);
|
---|
1924 | void print_win_params(WIN *p_win);
|
---|
1925 | void create_box(WIN *win, bool flag);
|
---|
1926 |
|
---|
1927 | int main(int argc, char *argv[])
|
---|
1928 | { WIN win;
|
---|
1929 | int ch;
|
---|
1930 |
|
---|
1931 | initscr(); /* Start curses mode */
|
---|
1932 | start_color(); /* Start the color functionality */
|
---|
1933 | cbreak(); /* Line buffering disabled, Pass on
|
---|
1934 | * everty thing to me */
|
---|
1935 | keypad(stdscr, TRUE); /* I need that nifty F1 */
|
---|
1936 | noecho();
|
---|
1937 | init_pair(1, COLOR_CYAN, COLOR_BLACK);
|
---|
1938 |
|
---|
1939 | /* Initialize the window parameters */
|
---|
1940 | init_win_params(&win);
|
---|
1941 | print_win_params(&win);
|
---|
1942 |
|
---|
1943 | attron(COLOR_PAIR(1));
|
---|
1944 | printw("Press F1 to exit");
|
---|
1945 | refresh();
|
---|
1946 | attroff(COLOR_PAIR(1));
|
---|
1947 |
|
---|
1948 | create_box(&win, TRUE);
|
---|
1949 | while((ch = getch()) != KEY_F(1))
|
---|
1950 | { switch(ch)
|
---|
1951 | { case KEY_LEFT:
|
---|
1952 | create_box(&win, FALSE);
|
---|
1953 | --win.startx;
|
---|
1954 | create_box(&win, TRUE);
|
---|
1955 | break;
|
---|
1956 | case KEY_RIGHT:
|
---|
1957 | create_box(&win, FALSE);
|
---|
1958 | ++win.startx;
|
---|
1959 | create_box(&win, TRUE);
|
---|
1960 | break;
|
---|
1961 | case KEY_UP:
|
---|
1962 | create_box(&win, FALSE);
|
---|
1963 | --win.starty;
|
---|
1964 | create_box(&win, TRUE);
|
---|
1965 | break;
|
---|
1966 | case KEY_DOWN:
|
---|
1967 | create_box(&win, FALSE);
|
---|
1968 | ++win.starty;
|
---|
1969 | create_box(&win, TRUE);
|
---|
1970 | break;
|
---|
1971 | }
|
---|
1972 | }
|
---|
1973 | endwin(); /* End curses mode */
|
---|
1974 | return 0;
|
---|
1975 | }
|
---|
1976 | void init_win_params(WIN *p_win)
|
---|
1977 | {
|
---|
1978 | p_win->height = 3;
|
---|
1979 | p_win->width = 10;
|
---|
1980 | p_win->starty = (LINES - p_win->height)/2;
|
---|
1981 | p_win->startx = (COLS - p_win->width)/2;
|
---|
1982 |
|
---|
1983 | p_win->border.ls = '|';
|
---|
1984 | p_win->border.rs = '|';
|
---|
1985 | p_win->border.ts = '-';
|
---|
1986 | p_win->border.bs = '-';
|
---|
1987 | p_win->border.tl = '+';
|
---|
1988 | p_win->border.tr = '+';
|
---|
1989 | p_win->border.bl = '+';
|
---|
1990 | p_win->border.br = '+';
|
---|
1991 |
|
---|
1992 | }
|
---|
1993 | void print_win_params(WIN *p_win)
|
---|
1994 | {
|
---|
1995 | #ifdef _DEBUG
|
---|
1996 | mvprintw(25, 0, "%d %d %d %d", p_win->startx, p_win->starty,
|
---|
1997 | p_win->width, p_win->height);
|
---|
1998 | refresh();
|
---|
1999 | #endif
|
---|
2000 | }
|
---|
2001 | void create_box(WIN *p_win, bool flag)
|
---|
2002 | { int i, j;
|
---|
2003 | int x, y, w, h;
|
---|
2004 |
|
---|
2005 | x = p_win->startx;
|
---|
2006 | y = p_win->starty;
|
---|
2007 | w = p_win->width;
|
---|
2008 | h = p_win->height;
|
---|
2009 |
|
---|
2010 | if(flag == TRUE)
|
---|
2011 | { mvaddch(y, x, p_win->border.tl);
|
---|
2012 | mvaddch(y, x + w, p_win->border.tr);
|
---|
2013 | mvaddch(y + h, x, p_win->border.bl);
|
---|
2014 | mvaddch(y + h, x + w, p_win->border.br);
|
---|
2015 | mvhline(y, x + 1, p_win->border.ts, w - 1);
|
---|
2016 | mvhline(y + h, x + 1, p_win->border.bs, w - 1);
|
---|
2017 | mvvline(y + 1, x, p_win->border.ls, h - 1);
|
---|
2018 | mvvline(y + 1, x + w, p_win->border.rs, h - 1);
|
---|
2019 |
|
---|
2020 | }
|
---|
2021 | else
|
---|
2022 | for(j = y; j <= y + h; ++j)
|
---|
2023 | for(i = x; i <= x + w; ++i)
|
---|
2024 | mvaddch(j, i, ' ');
|
---|
2025 |
|
---|
2026 | refresh();
|
---|
2027 |
|
---|
2028 | }</span></font>
|
---|
2029 | </pre></td>
|
---|
2030 | </tr>
|
---|
2031 | </table>
|
---|
2032 | </div>
|
---|
2033 | </div>
|
---|
2034 | </div>
|
---|
2035 | <div class="SECT1">
|
---|
2036 | <hr>
|
---|
2037 | <h2 class="SECT1"><a name="COLOR" id="COLOR">10. Colors</a></h2>
|
---|
2038 | <div class="SECT2">
|
---|
2039 | <h3 class="SECT2"><a name="COLORBASICS" id="COLORBASICS">10.1. The
|
---|
2040 | basics</a></h3>
|
---|
2041 | <p>Life seems dull with no colors. Curses has a nice mechanism to
|
---|
2042 | handle colors. Let's get into the thick of the things with a small
|
---|
2043 | program.</p>
|
---|
2044 | <div class="EXAMPLE"><a name="BSICO" id="BSICO"></a>
|
---|
2045 | <p><b>Example 9. A Simple Color example</b></p>
|
---|
2046 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
2047 | <tr>
|
---|
2048 | <td>
|
---|
2049 | <pre class="PROGRAMLISTING">
|
---|
2050 | <font color="#000000"><span class=
|
---|
2051 | "INLINEMEDIAOBJECT">#include <ncurses.h>
|
---|
2052 |
|
---|
2053 | void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string);
|
---|
2054 | int main(int argc, char *argv[])
|
---|
2055 | { initscr(); /* Start curses mode */
|
---|
2056 | if(has_colors() == FALSE)
|
---|
2057 | { endwin();
|
---|
2058 | printf("Your terminal does not support color\n");
|
---|
2059 | exit(1);
|
---|
2060 | }
|
---|
2061 | start_color(); /* Start color */
|
---|
2062 | init_pair(1, COLOR_RED, COLOR_BLACK);
|
---|
2063 |
|
---|
2064 | attron(COLOR_PAIR(1));
|
---|
2065 | print_in_middle(stdscr, LINES / 2, 0, 0, "Viola !!! In color ...");
|
---|
2066 | attroff(COLOR_PAIR(1));
|
---|
2067 | getch();
|
---|
2068 | endwin();
|
---|
2069 | }
|
---|
2070 | void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string)
|
---|
2071 | { int length, x, y;
|
---|
2072 | float temp;
|
---|
2073 |
|
---|
2074 | if(win == NULL)
|
---|
2075 | win = stdscr;
|
---|
2076 | getyx(win, y, x);
|
---|
2077 | if(startx != 0)
|
---|
2078 | x = startx;
|
---|
2079 | if(starty != 0)
|
---|
2080 | y = starty;
|
---|
2081 | if(width == 0)
|
---|
2082 | width = 80;
|
---|
2083 |
|
---|
2084 | length = strlen(string);
|
---|
2085 | temp = (width - length)/ 2;
|
---|
2086 | x = startx + (int)temp;
|
---|
2087 | mvwprintw(win, y, x, "%s", string);
|
---|
2088 | refresh();
|
---|
2089 | }
|
---|
2090 | </span></font>
|
---|
2091 | </pre></td>
|
---|
2092 | </tr>
|
---|
2093 | </table>
|
---|
2094 | </div>
|
---|
2095 | <p>As you can see, to start using color, you should first call the
|
---|
2096 | function <var class="LITERAL">start_color()</var>. After that, you
|
---|
2097 | can use color capabilities of your terminals using various
|
---|
2098 | functions. To find out whether a terminal has color capabilities or
|
---|
2099 | not, you can use <var class="LITERAL">has_colors()</var> function,
|
---|
2100 | which returns FALSE if the terminal does not support color.</p>
|
---|
2101 | <p>Curses initializes all the colors supported by terminal when
|
---|
2102 | start_color() is called. These can be accessed by the define
|
---|
2103 | constants like <var class="LITERAL">COLOR_BLACK</var> etc. Now to
|
---|
2104 | actually start using colors, you have to define pairs. Colors are
|
---|
2105 | always used in pairs. That means you have to use the function
|
---|
2106 | <var class="LITERAL">init_pair()</var> to define the foreground and
|
---|
2107 | background for the pair number you give. After that that pair
|
---|
2108 | number can be used as a normal attribute with <var class=
|
---|
2109 | "LITERAL">COLOR_PAIR()</var>function. This may seem to be
|
---|
2110 | cumbersome at first. But this elegant solution allows us to manage
|
---|
2111 | color pairs very easily. To appreciate it, you have to look into
|
---|
2112 | the the source code of "dialog", a utility for displaying dialog
|
---|
2113 | boxes from shell scripts. The developers have defined foreground
|
---|
2114 | and background combinations for all the colors they might need and
|
---|
2115 | initialized at the beginning. This makes it very easy to set
|
---|
2116 | attributes just by accessing a pair which we already have defined
|
---|
2117 | as a constant.</p>
|
---|
2118 | <p>The following colors are defined in <var class=
|
---|
2119 | "LITERAL">curses.h</var>. You can use these as parameters for
|
---|
2120 | various color functions.</p>
|
---|
2121 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
2122 | <tr>
|
---|
2123 | <td>
|
---|
2124 | <pre class="PROGRAMLISTING">
|
---|
2125 | <font color="#000000"> COLOR_BLACK 0
|
---|
2126 | COLOR_RED 1
|
---|
2127 | COLOR_GREEN 2
|
---|
2128 | COLOR_YELLOW 3
|
---|
2129 | COLOR_BLUE 4
|
---|
2130 | COLOR_MAGENTA 5
|
---|
2131 | COLOR_CYAN 6
|
---|
2132 | COLOR_WHITE 7</font>
|
---|
2133 | </pre></td>
|
---|
2134 | </tr>
|
---|
2135 | </table>
|
---|
2136 | </div>
|
---|
2137 | <div class="SECT2">
|
---|
2138 | <hr>
|
---|
2139 | <h3 class="SECT2"><a name="CHANGECOLORDEFS" id=
|
---|
2140 | "CHANGECOLORDEFS">10.2. Changing Color Definitions</a></h3>
|
---|
2141 | <p>The function <var class="LITERAL">init_color()</var>can be used
|
---|
2142 | to change the rgb values for the colors defined by curses
|
---|
2143 | initially. Say you wanted to lighten the intensity of red color by
|
---|
2144 | a minuscule. Then you can use this function as</p>
|
---|
2145 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
2146 | <tr>
|
---|
2147 | <td>
|
---|
2148 | <pre class="PROGRAMLISTING">
|
---|
2149 | <font color="#000000"> init_color(COLOR_RED, 700, 0, 0);
|
---|
2150 | /* param 1 : color name
|
---|
2151 | * param 2, 3, 4 : rgb content min = 0, max = 1000 */</font>
|
---|
2152 | </pre></td>
|
---|
2153 | </tr>
|
---|
2154 | </table>
|
---|
2155 | <p>If your terminal cannot change the color definitions, the
|
---|
2156 | function returns ERR. The function <var class=
|
---|
2157 | "LITERAL">can_change_color()</var> can be used to find out whether
|
---|
2158 | the terminal has the capability of changing color content or not.
|
---|
2159 | The rgb content is scaled from 0 to 1000. Initially RED color is
|
---|
2160 | defined with content 1000(r), 0(g), 0(b).</p>
|
---|
2161 | </div>
|
---|
2162 | <div class="SECT2">
|
---|
2163 | <hr>
|
---|
2164 | <h3 class="SECT2"><a name="COLORCONTENT" id="COLORCONTENT">10.3.
|
---|
2165 | Color Content</a></h3>
|
---|
2166 | <p>The functions <var class="LITERAL">color_content()</var> and
|
---|
2167 | <var class="LITERAL">pair_content()</var> can be used to find the
|
---|
2168 | color content and foreground, background combination for the
|
---|
2169 | pair.</p>
|
---|
2170 | </div>
|
---|
2171 | </div>
|
---|
2172 | <div class="SECT1">
|
---|
2173 | <hr>
|
---|
2174 | <h2 class="SECT1"><a name="KEYS" id="KEYS">11. Interfacing with the
|
---|
2175 | key board</a></h2>
|
---|
2176 | <div class="SECT2">
|
---|
2177 | <h3 class="SECT2"><a name="KEYSBASICS" id="KEYSBASICS">11.1. The
|
---|
2178 | Basics</a></h3>
|
---|
2179 | <p>No GUI is complete without a strong user interface and to
|
---|
2180 | interact with the user, a curses program should be sensitive to key
|
---|
2181 | presses or the mouse actions done by the user. Let's deal with the
|
---|
2182 | keys first.</p>
|
---|
2183 | <p>As you have seen in almost all of the above examples, it's very
|
---|
2184 | easy to get key input from the user. A simple way of getting key
|
---|
2185 | presses is to use <var class="LITERAL">getch()</var> function. The
|
---|
2186 | cbreak mode should be enabled to read keys when you are interested
|
---|
2187 | in reading individual key hits rather than complete lines of text
|
---|
2188 | (which usually end with a carriage return). keypad should be
|
---|
2189 | enabled to get the Functions keys, arrow keys etc. See the
|
---|
2190 | initialization section for details.</p>
|
---|
2191 | <p><var class="LITERAL">getch()</var> returns an integer
|
---|
2192 | corresponding to the key pressed. If it is a normal character, the
|
---|
2193 | integer value will be equivalent to the character. Otherwise it
|
---|
2194 | returns a number which can be matched with the constants defined in
|
---|
2195 | <var class="LITERAL">curses.h</var>. For example if the user
|
---|
2196 | presses F1, the integer returned is 265. This can be checked using
|
---|
2197 | the macro KEY_F() defined in curses.h. This makes reading keys
|
---|
2198 | portable and easy to manage.</p>
|
---|
2199 | <p>For example, if you call getch() like this</p>
|
---|
2200 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
2201 | <tr>
|
---|
2202 | <td>
|
---|
2203 | <pre class="PROGRAMLISTING">
|
---|
2204 | <font color="#000000"> int ch;
|
---|
2205 |
|
---|
2206 | ch = getch();</font>
|
---|
2207 | </pre></td>
|
---|
2208 | </tr>
|
---|
2209 | </table>
|
---|
2210 | <p>getch() will wait for the user to press a key, (unless you
|
---|
2211 | specified a timeout) and when user presses a key, the corresponding
|
---|
2212 | integer is returned. Then you can check the value returned with the
|
---|
2213 | constants defined in curses.h to match against the keys you
|
---|
2214 | want.</p>
|
---|
2215 | <p>The following code piece will do that job.</p>
|
---|
2216 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
2217 | <tr>
|
---|
2218 | <td>
|
---|
2219 | <pre class="PROGRAMLISTING">
|
---|
2220 | <font color="#000000"> if(ch == KEY_LEFT)
|
---|
2221 | printw("Left arrow is pressed\n");</font>
|
---|
2222 | </pre></td>
|
---|
2223 | </tr>
|
---|
2224 | </table>
|
---|
2225 | <p>Let's write a small program which creates a menu which can be
|
---|
2226 | navigated by up and down arrows.</p>
|
---|
2227 | </div>
|
---|
2228 | <div class="SECT2">
|
---|
2229 | <hr>
|
---|
2230 | <h3 class="SECT2"><a name="SIMPLEKEYEX" id="SIMPLEKEYEX">11.2. A
|
---|
2231 | Simple Key Usage example</a></h3>
|
---|
2232 | <div class="EXAMPLE"><a name="BSIKE" id="BSIKE"></a>
|
---|
2233 | <p><b>Example 10. A Simple Key Usage example</b></p>
|
---|
2234 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
2235 | <tr>
|
---|
2236 | <td>
|
---|
2237 | <pre class="PROGRAMLISTING">
|
---|
2238 | <font color="#000000"><span class=
|
---|
2239 | "INLINEMEDIAOBJECT">#include <stdio.h>
|
---|
2240 | #include <ncurses.h>
|
---|
2241 |
|
---|
2242 | #define WIDTH 30
|
---|
2243 | #define HEIGHT 10
|
---|
2244 |
|
---|
2245 | int startx = 0;
|
---|
2246 | int starty = 0;
|
---|
2247 |
|
---|
2248 | char *choices[] = {
|
---|
2249 | "Choice 1",
|
---|
2250 | "Choice 2",
|
---|
2251 | "Choice 3",
|
---|
2252 | "Choice 4",
|
---|
2253 | "Exit",
|
---|
2254 | };
|
---|
2255 | int n_choices = sizeof(choices) / sizeof(char *);
|
---|
2256 | void print_menu(WINDOW *menu_win, int highlight);
|
---|
2257 |
|
---|
2258 | int main()
|
---|
2259 | { WINDOW *menu_win;
|
---|
2260 | int highlight = 1;
|
---|
2261 | int choice = 0;
|
---|
2262 | int c;
|
---|
2263 |
|
---|
2264 | initscr();
|
---|
2265 | clear();
|
---|
2266 | noecho();
|
---|
2267 | cbreak(); /* Line buffering disabled. pass on everything */
|
---|
2268 | startx = (80 - WIDTH) / 2;
|
---|
2269 | starty = (24 - HEIGHT) / 2;
|
---|
2270 |
|
---|
2271 | menu_win = newwin(HEIGHT, WIDTH, starty, startx);
|
---|
2272 | keypad(menu_win, TRUE);
|
---|
2273 | mvprintw(0, 0, "Use arrow keys to go up and down, Press enter to select a choice");
|
---|
2274 | refresh();
|
---|
2275 | print_menu(menu_win, highlight);
|
---|
2276 | while(1)
|
---|
2277 | { c = wgetch(menu_win);
|
---|
2278 | switch(c)
|
---|
2279 | { case KEY_UP:
|
---|
2280 | if(highlight == 1)
|
---|
2281 | highlight = n_choices;
|
---|
2282 | else
|
---|
2283 | --highlight;
|
---|
2284 | break;
|
---|
2285 | case KEY_DOWN:
|
---|
2286 | if(highlight == n_choices)
|
---|
2287 | highlight = 1;
|
---|
2288 | else
|
---|
2289 | ++highlight;
|
---|
2290 | break;
|
---|
2291 | case 10:
|
---|
2292 | choice = highlight;
|
---|
2293 | break;
|
---|
2294 | default:
|
---|
2295 | mvprintw(24, 0, "Charcter pressed is = %3d Hopefully it can be printed as '%c'", c, c);
|
---|
2296 | refresh();
|
---|
2297 | break;
|
---|
2298 | }
|
---|
2299 | print_menu(menu_win, highlight);
|
---|
2300 | if(choice != 0) /* User did a choice come out of the infinite loop */
|
---|
2301 | break;
|
---|
2302 | }
|
---|
2303 | mvprintw(23, 0, "You chose choice %d with choice string %s\n", choice, choices[choice - 1]);
|
---|
2304 | clrtoeol();
|
---|
2305 | refresh();
|
---|
2306 | endwin();
|
---|
2307 | return 0;
|
---|
2308 | }
|
---|
2309 |
|
---|
2310 |
|
---|
2311 | void print_menu(WINDOW *menu_win, int highlight)
|
---|
2312 | {
|
---|
2313 | int x, y, i;
|
---|
2314 |
|
---|
2315 | x = 2;
|
---|
2316 | y = 2;
|
---|
2317 | box(menu_win, 0, 0);
|
---|
2318 | for(i = 0; i < n_choices; ++i)
|
---|
2319 | { if(highlight == i + 1) /* High light the present choice */
|
---|
2320 | { wattron(menu_win, A_REVERSE);
|
---|
2321 | mvwprintw(menu_win, y, x, "%s", choices[i]);
|
---|
2322 | wattroff(menu_win, A_REVERSE);
|
---|
2323 | }
|
---|
2324 | else
|
---|
2325 | mvwprintw(menu_win, y, x, "%s", choices[i]);
|
---|
2326 | ++y;
|
---|
2327 | }
|
---|
2328 | wrefresh(menu_win);
|
---|
2329 | }
|
---|
2330 | </span></font>
|
---|
2331 | </pre></td>
|
---|
2332 | </tr>
|
---|
2333 | </table>
|
---|
2334 | </div>
|
---|
2335 | </div>
|
---|
2336 | </div>
|
---|
2337 | <div class="SECT1">
|
---|
2338 | <hr>
|
---|
2339 | <h2 class="SECT1"><a name="MOUSE" id="MOUSE">12. Interfacing with
|
---|
2340 | the mouse</a></h2>
|
---|
2341 | <p>Now that you have seen how to get keys, lets do the same thing
|
---|
2342 | from mouse. Usually each UI allows the user to interact with both
|
---|
2343 | keyboard and mouse.</p>
|
---|
2344 | <div class="SECT2">
|
---|
2345 | <hr>
|
---|
2346 | <h3 class="SECT2"><a name="MOUSEBASICS" id="MOUSEBASICS">12.1. The
|
---|
2347 | Basics</a></h3>
|
---|
2348 | <p>Before you do any thing else, the events you want to receive
|
---|
2349 | have to be enabled with <var class="LITERAL">mousemask()</var>.</p>
|
---|
2350 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
2351 | <tr>
|
---|
2352 | <td>
|
---|
2353 | <pre class="PROGRAMLISTING">
|
---|
2354 | <font color=
|
---|
2355 | "#000000"> mousemask( mmask_t newmask, /* The events you want to listen to */
|
---|
2356 | mmask_t *oldmask) /* The old events mask */</font>
|
---|
2357 | </pre></td>
|
---|
2358 | </tr>
|
---|
2359 | </table>
|
---|
2360 | <p>The first parameter to above function is a bit mask of events
|
---|
2361 | you would like to listen. By default, all the events are turned
|
---|
2362 | off. The bit mask <var class="LITERAL">ALL_MOUSE_EVENTS</var> can
|
---|
2363 | be used to get all the events.</p>
|
---|
2364 | <p>The following are all the event masks:</p>
|
---|
2365 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
2366 | <tr>
|
---|
2367 | <td>
|
---|
2368 | <pre class="PROGRAMLISTING">
|
---|
2369 | <font color="#000000"> Name Description
|
---|
2370 | ---------------------------------------------------------------------
|
---|
2371 | BUTTON1_PRESSED mouse button 1 down
|
---|
2372 | BUTTON1_RELEASED mouse button 1 up
|
---|
2373 | BUTTON1_CLICKED mouse button 1 clicked
|
---|
2374 | BUTTON1_DOUBLE_CLICKED mouse button 1 double clicked
|
---|
2375 | BUTTON1_TRIPLE_CLICKED mouse button 1 triple clicked
|
---|
2376 | BUTTON2_PRESSED mouse button 2 down
|
---|
2377 | BUTTON2_RELEASED mouse button 2 up
|
---|
2378 | BUTTON2_CLICKED mouse button 2 clicked
|
---|
2379 | BUTTON2_DOUBLE_CLICKED mouse button 2 double clicked
|
---|
2380 | BUTTON2_TRIPLE_CLICKED mouse button 2 triple clicked
|
---|
2381 | BUTTON3_PRESSED mouse button 3 down
|
---|
2382 | BUTTON3_RELEASED mouse button 3 up
|
---|
2383 | BUTTON3_CLICKED mouse button 3 clicked
|
---|
2384 | BUTTON3_DOUBLE_CLICKED mouse button 3 double clicked
|
---|
2385 | BUTTON3_TRIPLE_CLICKED mouse button 3 triple clicked
|
---|
2386 | BUTTON4_PRESSED mouse button 4 down
|
---|
2387 | BUTTON4_RELEASED mouse button 4 up
|
---|
2388 | BUTTON4_CLICKED mouse button 4 clicked
|
---|
2389 | BUTTON4_DOUBLE_CLICKED mouse button 4 double clicked
|
---|
2390 | BUTTON4_TRIPLE_CLICKED mouse button 4 triple clicked
|
---|
2391 | BUTTON_SHIFT shift was down during button state change
|
---|
2392 | BUTTON_CTRL control was down during button state change
|
---|
2393 | BUTTON_ALT alt was down during button state change
|
---|
2394 | ALL_MOUSE_EVENTS report all button state changes
|
---|
2395 | REPORT_MOUSE_POSITION report mouse movement</font>
|
---|
2396 | </pre></td>
|
---|
2397 | </tr>
|
---|
2398 | </table>
|
---|
2399 | </div>
|
---|
2400 | <div class="SECT2">
|
---|
2401 | <hr>
|
---|
2402 | <h3 class="SECT2"><a name="GETTINGEVENTS" id="GETTINGEVENTS">12.2.
|
---|
2403 | Getting the events</a></h3>
|
---|
2404 | <p>Once a class of mouse events have been enabled, getch() class of
|
---|
2405 | functions return KEY_MOUSE every time some mouse event happens.
|
---|
2406 | Then the mouse event can be retrieved with <var class=
|
---|
2407 | "LITERAL">getmouse()</var>.</p>
|
---|
2408 | <p>The code approximately looks like this:</p>
|
---|
2409 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
2410 | <tr>
|
---|
2411 | <td>
|
---|
2412 | <pre class="PROGRAMLISTING">
|
---|
2413 | <font color="#000000"> MEVENT event;
|
---|
2414 |
|
---|
2415 | ch = getch();
|
---|
2416 | if(ch == KEY_MOUSE)
|
---|
2417 | if(getmouse(&event) == OK)
|
---|
2418 | . /* Do some thing with the event */
|
---|
2419 | .
|
---|
2420 | .</font>
|
---|
2421 | </pre></td>
|
---|
2422 | </tr>
|
---|
2423 | </table>
|
---|
2424 | <p>getmouse() returns the event into the pointer given to it. It's
|
---|
2425 | a structure which contains</p>
|
---|
2426 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
2427 | <tr>
|
---|
2428 | <td>
|
---|
2429 | <pre class="PROGRAMLISTING">
|
---|
2430 | <font color="#000000"> typedef struct
|
---|
2431 | {
|
---|
2432 | short id; /* ID to distinguish multiple devices */
|
---|
2433 | int x, y, z; /* event coordinates */
|
---|
2434 | mmask_t bstate; /* button state bits */
|
---|
2435 | } </font>
|
---|
2436 | </pre></td>
|
---|
2437 | </tr>
|
---|
2438 | </table>
|
---|
2439 | <p>The <var class="LITERAL">bstate</var> is the main variable we
|
---|
2440 | are interested in. It tells the button state of the mouse.</p>
|
---|
2441 | <p>Then with a code snippet like the following, we can find out
|
---|
2442 | what happened.</p>
|
---|
2443 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
2444 | <tr>
|
---|
2445 | <td>
|
---|
2446 | <pre class="PROGRAMLISTING">
|
---|
2447 | <font color="#000000"> if(event.bstate & BUTTON1_PRESSED)
|
---|
2448 | printw("Left Button Pressed");</font>
|
---|
2449 | </pre></td>
|
---|
2450 | </tr>
|
---|
2451 | </table>
|
---|
2452 | </div>
|
---|
2453 | <div class="SECT2">
|
---|
2454 | <hr>
|
---|
2455 | <h3 class="SECT2"><a name="MOUSETOGETHER" id="MOUSETOGETHER">12.3.
|
---|
2456 | Putting it all Together</a></h3>
|
---|
2457 | <p>That's pretty much interfacing with mouse. Let's create the same
|
---|
2458 | menu and enable mouse interaction. To make things simpler, key
|
---|
2459 | handling is removed.</p>
|
---|
2460 | <div class="EXAMPLE"><a name="BMOME" id="BMOME"></a>
|
---|
2461 | <p><b>Example 11. Access the menu with mouse !!!</b></p>
|
---|
2462 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
2463 | <tr>
|
---|
2464 | <td>
|
---|
2465 | <pre class="PROGRAMLISTING">
|
---|
2466 | <font color="#000000"><span class=
|
---|
2467 | "INLINEMEDIAOBJECT">#include <ncurses.h>
|
---|
2468 |
|
---|
2469 | #define WIDTH 30
|
---|
2470 | #define HEIGHT 10
|
---|
2471 |
|
---|
2472 | int startx = 0;
|
---|
2473 | int starty = 0;
|
---|
2474 |
|
---|
2475 | char *choices[] = { "Choice 1",
|
---|
2476 | "Choice 2",
|
---|
2477 | "Choice 3",
|
---|
2478 | "Choice 4",
|
---|
2479 | "Exit",
|
---|
2480 | };
|
---|
2481 |
|
---|
2482 | int n_choices = sizeof(choices) / sizeof(char *);
|
---|
2483 |
|
---|
2484 | void print_menu(WINDOW *menu_win, int highlight);
|
---|
2485 | void report_choice(int mouse_x, int mouse_y, int *p_choice);
|
---|
2486 |
|
---|
2487 | int main()
|
---|
2488 | { int c, choice = 0;
|
---|
2489 | WINDOW *menu_win;
|
---|
2490 | MEVENT event;
|
---|
2491 |
|
---|
2492 | /* Initialize curses */
|
---|
2493 | initscr();
|
---|
2494 | clear();
|
---|
2495 | noecho();
|
---|
2496 | cbreak(); //Line buffering disabled. pass on everything
|
---|
2497 |
|
---|
2498 | /* Try to put the window in the middle of screen */
|
---|
2499 | startx = (80 - WIDTH) / 2;
|
---|
2500 | starty = (24 - HEIGHT) / 2;
|
---|
2501 |
|
---|
2502 | attron(A_REVERSE);
|
---|
2503 | mvprintw(23, 1, "Click on Exit to quit (Works best in a virtual console)");
|
---|
2504 | refresh();
|
---|
2505 | attroff(A_REVERSE);
|
---|
2506 |
|
---|
2507 | /* Print the menu for the first time */
|
---|
2508 | menu_win = newwin(HEIGHT, WIDTH, starty, startx);
|
---|
2509 | print_menu(menu_win, 1);
|
---|
2510 | /* Get all the mouse events */
|
---|
2511 | mousemask(ALL_MOUSE_EVENTS, NULL);
|
---|
2512 |
|
---|
2513 | while(1)
|
---|
2514 | { c = wgetch(menu_win);
|
---|
2515 | switch(c)
|
---|
2516 | { case KEY_MOUSE:
|
---|
2517 | if(getmouse(&event) == OK)
|
---|
2518 | { /* When the user clicks left mouse button */
|
---|
2519 | if(event.bstate & BUTTON1_PRESSED)
|
---|
2520 | { report_choice(event.x + 1, event.y + 1, &choice);
|
---|
2521 | if(choice == -1) //Exit chosen
|
---|
2522 | goto end;
|
---|
2523 | mvprintw(22, 1, "Choice made is : %d String Chosen is \"%10s\"", choice, choices[choice - 1]);
|
---|
2524 | refresh();
|
---|
2525 | }
|
---|
2526 | }
|
---|
2527 | print_menu(menu_win, choice);
|
---|
2528 | break;
|
---|
2529 | }
|
---|
2530 | }
|
---|
2531 | end:
|
---|
2532 | endwin();
|
---|
2533 | return 0;
|
---|
2534 | }
|
---|
2535 |
|
---|
2536 |
|
---|
2537 | void print_menu(WINDOW *menu_win, int highlight)
|
---|
2538 | {
|
---|
2539 | int x, y, i;
|
---|
2540 |
|
---|
2541 | x = 2;
|
---|
2542 | y = 2;
|
---|
2543 | box(menu_win, 0, 0);
|
---|
2544 | for(i = 0; i < n_choices; ++i)
|
---|
2545 | { if(highlight == i + 1)
|
---|
2546 | { wattron(menu_win, A_REVERSE);
|
---|
2547 | mvwprintw(menu_win, y, x, "%s", choices[i]);
|
---|
2548 | wattroff(menu_win, A_REVERSE);
|
---|
2549 | }
|
---|
2550 | else
|
---|
2551 | mvwprintw(menu_win, y, x, "%s", choices[i]);
|
---|
2552 | ++y;
|
---|
2553 | }
|
---|
2554 | wrefresh(menu_win);
|
---|
2555 | }
|
---|
2556 |
|
---|
2557 | /* Report the choice according to mouse position */
|
---|
2558 | void report_choice(int mouse_x, int mouse_y, int *p_choice)
|
---|
2559 | { int i,j, choice;
|
---|
2560 |
|
---|
2561 | i = startx + 2;
|
---|
2562 | j = starty + 3;
|
---|
2563 |
|
---|
2564 | for(choice = 0; choice < n_choices; ++choice)
|
---|
2565 | if(mouse_y == j + choice && mouse_x >= i && mouse_x <= i + strlen(choices[choice]))
|
---|
2566 | { if(choice == n_choices - 1)
|
---|
2567 | *p_choice = -1;
|
---|
2568 | else
|
---|
2569 | *p_choice = choice + 1;
|
---|
2570 | break;
|
---|
2571 | }
|
---|
2572 | }</span></font>
|
---|
2573 | </pre></td>
|
---|
2574 | </tr>
|
---|
2575 | </table>
|
---|
2576 | </div>
|
---|
2577 | </div>
|
---|
2578 | <div class="SECT2">
|
---|
2579 | <hr>
|
---|
2580 | <h3 class="SECT2"><a name="MISCMOUSEFUNCS" id=
|
---|
2581 | "MISCMOUSEFUNCS">12.4. Miscellaneous Functions</a></h3>
|
---|
2582 | <p>The functions mouse_trafo() and wmouse_trafo() can be used to
|
---|
2583 | convert to mouse co-ordinates to screen relative co-ordinates. See
|
---|
2584 | curs_mouse(3X) man page for details.</p>
|
---|
2585 | <p>The mouseinterval function sets the maximum time (in thousands
|
---|
2586 | of a second) that can elapse between press and release events in
|
---|
2587 | order for them to be recognized as a click. This function returns
|
---|
2588 | the previous interval value. The default is one fifth of a
|
---|
2589 | second.</p>
|
---|
2590 | </div>
|
---|
2591 | </div>
|
---|
2592 | <div class="SECT1">
|
---|
2593 | <hr>
|
---|
2594 | <h2 class="SECT1"><a name="SCREEN" id="SCREEN">13. Screen
|
---|
2595 | Manipulation</a></h2>
|
---|
2596 | <p>In this section, we will look into some functions, which allow
|
---|
2597 | us to manage the screen efficiently and to write some fancy
|
---|
2598 | programs. This is especially important in writing games.</p>
|
---|
2599 | <div class="SECT2">
|
---|
2600 | <hr>
|
---|
2601 | <h3 class="SECT2"><a name="GETYX" id="GETYX">13.1. getyx()
|
---|
2602 | functions</a></h3>
|
---|
2603 | <p>The function <var class="LITERAL">getyx()</var> can be used to
|
---|
2604 | find out the present cursor co-ordinates. It will fill the values
|
---|
2605 | of x and y co-ordinates in the arguments given to it. Since getyx()
|
---|
2606 | is a macro you don't have to pass the address of the variables. It
|
---|
2607 | can be called as</p>
|
---|
2608 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
2609 | <tr>
|
---|
2610 | <td>
|
---|
2611 | <pre class="PROGRAMLISTING">
|
---|
2612 | <font color="#000000"> getyx(win, y, x);
|
---|
2613 | /* win: window pointer
|
---|
2614 | * y, x: y, x co-ordinates will be put into this variables
|
---|
2615 | */</font>
|
---|
2616 | </pre></td>
|
---|
2617 | </tr>
|
---|
2618 | </table>
|
---|
2619 | <p>The function getparyx() gets the beginning co-ordinates of the
|
---|
2620 | sub window relative to the main window. This is some times useful
|
---|
2621 | to update a sub window. When designing fancy stuff like writing
|
---|
2622 | multiple menus, it becomes difficult to store the menu positions,
|
---|
2623 | their first option co-ordinates etc. A simple solution to this
|
---|
2624 | problem, is to create menus in sub windows and later find the
|
---|
2625 | starting co-ordinates of the menus by using getparyx().</p>
|
---|
2626 | <p>The functions getbegyx() and getmaxyx() store current window's
|
---|
2627 | beginning and maximum co-ordinates. These functions are useful in
|
---|
2628 | the same way as above in managing the windows and sub windows
|
---|
2629 | effectively.</p>
|
---|
2630 | </div>
|
---|
2631 | <div class="SECT2">
|
---|
2632 | <hr>
|
---|
2633 | <h3 class="SECT2"><a name="SCREENDUMP" id="SCREENDUMP">13.2. Screen
|
---|
2634 | Dumping</a></h3>
|
---|
2635 | <p>While writing games, some times it becomes necessary to store
|
---|
2636 | the state of the screen and restore it back to the same state. The
|
---|
2637 | function scr_dump() can be used to dump the screen contents to a
|
---|
2638 | file given as an argument. Later it can be restored by scr_restore
|
---|
2639 | function. These two simple functions can be used effectively to
|
---|
2640 | maintain a fast moving game with changing scenarios.</p>
|
---|
2641 | </div>
|
---|
2642 | <div class="SECT2">
|
---|
2643 | <hr>
|
---|
2644 | <h3 class="SECT2"><a name="WINDOWDUMP" id="WINDOWDUMP">13.3. Window
|
---|
2645 | Dumping</a></h3>
|
---|
2646 | <p>To store and restore windows, the functions <var class=
|
---|
2647 | "LITERAL">putwin()</var> and <var class="LITERAL">getwin()</var>
|
---|
2648 | can be used. <var class="LITERAL">putwin()</var> puts the present
|
---|
2649 | window state into a file, which can be later restored by
|
---|
2650 | <var class="LITERAL">getwin()</var>.</p>
|
---|
2651 | <p>The function <var class="LITERAL">copywin()</var> can be used to
|
---|
2652 | copy a window completely onto another window. It takes the source
|
---|
2653 | and destination windows as parameters and according to the
|
---|
2654 | rectangle specified, it copies the rectangular region from source
|
---|
2655 | to destination window. It's last parameter specifies whether to
|
---|
2656 | overwrite or just overlay the contents on to the destination
|
---|
2657 | window. If this argument is true, then the copying is
|
---|
2658 | non-destructive.</p>
|
---|
2659 | </div>
|
---|
2660 | </div>
|
---|
2661 | <div class="SECT1">
|
---|
2662 | <hr>
|
---|
2663 | <h2 class="SECT1"><a name="MISC" id="MISC">14. Miscellaneous
|
---|
2664 | features</a></h2>
|
---|
2665 | <p>Now you know enough features to write a good curses program,
|
---|
2666 | with all bells and whistles. There are some miscellaneous functions
|
---|
2667 | which are useful in various cases. Let's go headlong into some of
|
---|
2668 | those.</p>
|
---|
2669 | <div class="SECT2">
|
---|
2670 | <hr>
|
---|
2671 | <h3 class="SECT2"><a name="CURSSET" id="CURSSET">14.1.
|
---|
2672 | curs_set()</a></h3>
|
---|
2673 | <p>This function can be used to make the cursor invisible. The
|
---|
2674 | parameter to this function should be</p>
|
---|
2675 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
2676 | <tr>
|
---|
2677 | <td>
|
---|
2678 | <pre class="PROGRAMLISTING">
|
---|
2679 | <font color="#000000"> 0 : invisible or
|
---|
2680 | 1 : normal or
|
---|
2681 | 2 : very visible.</font>
|
---|
2682 | </pre></td>
|
---|
2683 | </tr>
|
---|
2684 | </table>
|
---|
2685 | </div>
|
---|
2686 | <div class="SECT2">
|
---|
2687 | <hr>
|
---|
2688 | <h3 class="SECT2"><a name="TEMPLEAVE" id="TEMPLEAVE">14.2.
|
---|
2689 | Temporarily Leaving Curses mode</a></h3>
|
---|
2690 | <p>Some times you may want to get back to cooked mode (normal line
|
---|
2691 | buffering mode) temporarily. In such a case you will first need to
|
---|
2692 | save the tty modes with a call to <var class=
|
---|
2693 | "LITERAL">def_prog_mode()</var> and then call <var class=
|
---|
2694 | "LITERAL">endwin()</var> to end the curses mode. This will leave
|
---|
2695 | you in the original tty mode. To get back to curses once you are
|
---|
2696 | done, call <var class="LITERAL">reset_prog_mode()</var> . This
|
---|
2697 | function returns the tty to the state stored by <var class=
|
---|
2698 | "LITERAL">def_prog_mode()</var>. Then do refresh(), and you are
|
---|
2699 | back to the curses mode. Here is an example showing the sequence of
|
---|
2700 | things to be done.</p>
|
---|
2701 | <div class="EXAMPLE"><a name="BTELE" id="BTELE"></a>
|
---|
2702 | <p><b>Example 12. Temporarily Leaving Curses Mode</b></p>
|
---|
2703 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
2704 | <tr>
|
---|
2705 | <td>
|
---|
2706 | <pre class="PROGRAMLISTING">
|
---|
2707 | <font color="#000000"><span class=
|
---|
2708 | "INLINEMEDIAOBJECT">#include <ncurses.h>
|
---|
2709 |
|
---|
2710 | int main()
|
---|
2711 | {
|
---|
2712 | initscr(); /* Start curses mode */
|
---|
2713 | printw("Hello World !!!\n"); /* Print Hello World */
|
---|
2714 | refresh(); /* Print it on to the real screen */
|
---|
2715 | def_prog_mode(); /* Save the tty modes */
|
---|
2716 | endwin(); /* End curses mode temporarily */
|
---|
2717 | system("/bin/sh"); /* Do whatever you like in cooked mode */
|
---|
2718 | reset_prog_mode(); /* Return to the previous tty mode*/
|
---|
2719 | /* stored by def_prog_mode() */
|
---|
2720 | refresh(); /* Do refresh() to restore the */
|
---|
2721 | /* Screen contents */
|
---|
2722 | printw("Another String\n"); /* Back to curses use the full */
|
---|
2723 | refresh(); /* capabilities of curses */
|
---|
2724 | endwin(); /* End curses mode */
|
---|
2725 |
|
---|
2726 | return 0;
|
---|
2727 | }</span></font>
|
---|
2728 | </pre></td>
|
---|
2729 | </tr>
|
---|
2730 | </table>
|
---|
2731 | </div>
|
---|
2732 | </div>
|
---|
2733 | <div class="SECT2">
|
---|
2734 | <hr>
|
---|
2735 | <h3 class="SECT2"><a name="ACSVARS" id="ACSVARS">14.3. ACS_
|
---|
2736 | variables</a></h3>
|
---|
2737 | <p>If you have ever programmed in DOS, you know about those nifty
|
---|
2738 | characters in extended character set. They are printable only on
|
---|
2739 | some terminals. NCURSES functions like <var class=
|
---|
2740 | "LITERAL">box()</var> use these characters. All these variables
|
---|
2741 | start with ACS meaning alternative character set. You might have
|
---|
2742 | noticed me using these characters in some of the programs above.
|
---|
2743 | Here's an example showing all the characters.</p>
|
---|
2744 | <div class="EXAMPLE"><a name="BACSVARS" id="BACSVARS"></a>
|
---|
2745 | <p><b>Example 13. ACS Variables Example</b></p>
|
---|
2746 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
2747 | <tr>
|
---|
2748 | <td>
|
---|
2749 | <pre class="PROGRAMLISTING">
|
---|
2750 | <font color="#000000"><span class=
|
---|
2751 | "INLINEMEDIAOBJECT">#include <ncurses.h>
|
---|
2752 |
|
---|
2753 | int main()
|
---|
2754 | {
|
---|
2755 | initscr();
|
---|
2756 |
|
---|
2757 | printw("Upper left corner "); addch(ACS_ULCORNER); printw("\n");
|
---|
2758 | printw("Lower left corner "); addch(ACS_LLCORNER); printw("\n");
|
---|
2759 | printw("Lower right corner "); addch(ACS_LRCORNER); printw("\n");
|
---|
2760 | printw("Tee pointing right "); addch(ACS_LTEE); printw("\n");
|
---|
2761 | printw("Tee pointing left "); addch(ACS_RTEE); printw("\n");
|
---|
2762 | printw("Tee pointing up "); addch(ACS_BTEE); printw("\n");
|
---|
2763 | printw("Tee pointing down "); addch(ACS_TTEE); printw("\n");
|
---|
2764 | printw("Horizontal line "); addch(ACS_HLINE); printw("\n");
|
---|
2765 | printw("Vertical line "); addch(ACS_VLINE); printw("\n");
|
---|
2766 | printw("Large Plus or cross over "); addch(ACS_PLUS); printw("\n");
|
---|
2767 | printw("Scan Line 1 "); addch(ACS_S1); printw("\n");
|
---|
2768 | printw("Scan Line 3 "); addch(ACS_S3); printw("\n");
|
---|
2769 | printw("Scan Line 7 "); addch(ACS_S7); printw("\n");
|
---|
2770 | printw("Scan Line 9 "); addch(ACS_S9); printw("\n");
|
---|
2771 | printw("Diamond "); addch(ACS_DIAMOND); printw("\n");
|
---|
2772 | printw("Checker board (stipple) "); addch(ACS_CKBOARD); printw("\n");
|
---|
2773 | printw("Degree Symbol "); addch(ACS_DEGREE); printw("\n");
|
---|
2774 | printw("Plus/Minus Symbol "); addch(ACS_PLMINUS); printw("\n");
|
---|
2775 | printw("Bullet "); addch(ACS_BULLET); printw("\n");
|
---|
2776 | printw("Arrow Pointing Left "); addch(ACS_LARROW); printw("\n");
|
---|
2777 | printw("Arrow Pointing Right "); addch(ACS_RARROW); printw("\n");
|
---|
2778 | printw("Arrow Pointing Down "); addch(ACS_DARROW); printw("\n");
|
---|
2779 | printw("Arrow Pointing Up "); addch(ACS_UARROW); printw("\n");
|
---|
2780 | printw("Board of squares "); addch(ACS_BOARD); printw("\n");
|
---|
2781 | printw("Lantern Symbol "); addch(ACS_LANTERN); printw("\n");
|
---|
2782 | printw("Solid Square Block "); addch(ACS_BLOCK); printw("\n");
|
---|
2783 | printw("Less/Equal sign "); addch(ACS_LEQUAL); printw("\n");
|
---|
2784 | printw("Greater/Equal sign "); addch(ACS_GEQUAL); printw("\n");
|
---|
2785 | printw("Pi "); addch(ACS_PI); printw("\n");
|
---|
2786 | printw("Not equal "); addch(ACS_NEQUAL); printw("\n");
|
---|
2787 | printw("UK pound sign "); addch(ACS_STERLING); printw("\n");
|
---|
2788 |
|
---|
2789 | refresh();
|
---|
2790 | getch();
|
---|
2791 | endwin();
|
---|
2792 |
|
---|
2793 | return 0;
|
---|
2794 | }</span></font>
|
---|
2795 | </pre></td>
|
---|
2796 | </tr>
|
---|
2797 | </table>
|
---|
2798 | </div>
|
---|
2799 | </div>
|
---|
2800 | </div>
|
---|
2801 | <div class="SECT1">
|
---|
2802 | <hr>
|
---|
2803 | <h2 class="SECT1"><a name="OTHERLIB" id="OTHERLIB">15. Other
|
---|
2804 | libraries</a></h2>
|
---|
2805 | <p>Apart from the curses library, there are few text mode
|
---|
2806 | libraries, which provide more functionality and a lot of features.
|
---|
2807 | The following sections explain three standard libraries which are
|
---|
2808 | usually distributed along with curses.</p>
|
---|
2809 | </div>
|
---|
2810 | <div class="SECT1">
|
---|
2811 | <hr>
|
---|
2812 | <h2 class="SECT1"><a name="PANELS" id="PANELS">16. Panel
|
---|
2813 | Library</a></h2>
|
---|
2814 | <p>Now that you are proficient in curses, you wanted to do some
|
---|
2815 | thing big. You created a lot of overlapping windows to give a
|
---|
2816 | professional windows-type look. Unfortunately, it soon becomes
|
---|
2817 | difficult to manage these. The multiple refreshes, updates plunge
|
---|
2818 | you into a nightmare. The overlapping windows create blotches,
|
---|
2819 | whenever you forget to refresh the windows in the proper order.</p>
|
---|
2820 | <p>Don't despair. There's an elegant solution provided in panels
|
---|
2821 | library. In the words of developers of ncurses</p>
|
---|
2822 | <p><em>When your interface design is such that windows may dive
|
---|
2823 | deeper into the visibility stack or pop to the top at runtime, the
|
---|
2824 | resulting book-keeping can be tedious and difficult to get right.
|
---|
2825 | Hence the panels library.</em></p>
|
---|
2826 | <p>If you have lot of overlapping windows, then panels library is
|
---|
2827 | the way to go. It obviates the need of doing series of
|
---|
2828 | wnoutrefresh(), doupdate() and relieves the burden of doing it
|
---|
2829 | correctly(bottom up). The library maintains information about the
|
---|
2830 | order of windows, their overlapping and update the screen properly.
|
---|
2831 | So why wait? Let's take a close peek into panels.</p>
|
---|
2832 | <div class="SECT2">
|
---|
2833 | <hr>
|
---|
2834 | <h3 class="SECT2"><a name="PANELBASICS" id="PANELBASICS">16.1. The
|
---|
2835 | Basics</a></h3>
|
---|
2836 | <p>Panel object is a window that is implicitly treated as part of a
|
---|
2837 | deck including all other panel objects. The deck is treated as a
|
---|
2838 | stack with the top panel being completely visible and the other
|
---|
2839 | panels may or may not be obscured according to their positions. So
|
---|
2840 | the basic idea is to create a stack of overlapping panels and use
|
---|
2841 | panels library to display them correctly. There is a function
|
---|
2842 | similar to refresh() which, when called , displays panels in the
|
---|
2843 | correct order. Functions are provided to hide or show panels, move
|
---|
2844 | panels, change its size etc.. The overlapping problem is managed by
|
---|
2845 | the panels library during all the calls to these functions.</p>
|
---|
2846 | <p>The general flow of a panel program goes like this:</p>
|
---|
2847 | <ol type="1">
|
---|
2848 | <li>
|
---|
2849 | <p>Create the windows (with newwin()) to be attached to the
|
---|
2850 | panels.</p>
|
---|
2851 | </li>
|
---|
2852 | <li>
|
---|
2853 | <p>Create panels with the chosen visibility order. Stack them up
|
---|
2854 | according to the desired visibility. The function new_panel() is
|
---|
2855 | used to created panels.</p>
|
---|
2856 | </li>
|
---|
2857 | <li>
|
---|
2858 | <p>Call update_panels() to write the panels to the virtual screen
|
---|
2859 | in correct visibility order. Do a doupdate() to show it on the
|
---|
2860 | screen.</p>
|
---|
2861 | </li>
|
---|
2862 | <li>
|
---|
2863 | <p>Mainpulate the panels with show_panel(), hide_panel(),
|
---|
2864 | move_panel() etc. Make use of helper functions like panel_hidden()
|
---|
2865 | and panel_window(). Make use of user pointer to store custom data
|
---|
2866 | for a panel. Use the functions set_panel_userptr() and
|
---|
2867 | panel_userptr() to set and get the user pointer for a panel.</p>
|
---|
2868 | </li>
|
---|
2869 | <li>
|
---|
2870 | <p>When you are done with the panel use del_panel() to delete the
|
---|
2871 | panel.</p>
|
---|
2872 | </li>
|
---|
2873 | </ol>
|
---|
2874 | <p>Let's make the concepts clear, with some programs. The following
|
---|
2875 | is a simple program which creates 3 overlapping panels and shows
|
---|
2876 | them on the screen.</p>
|
---|
2877 | </div>
|
---|
2878 | <div class="SECT2">
|
---|
2879 | <hr>
|
---|
2880 | <h3 class="SECT2"><a name="COMPILEPANELS" id="COMPILEPANELS">16.2.
|
---|
2881 | Compiling With the Panels Library</a></h3>
|
---|
2882 | <p>To use panels library functions, you have to include panel.h and
|
---|
2883 | to link the program with panels library the flag -lpanel should be
|
---|
2884 | added along with -lncurses in that order.</p>
|
---|
2885 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
2886 | <tr>
|
---|
2887 | <td>
|
---|
2888 | <pre class="PROGRAMLISTING">
|
---|
2889 | <font color="#000000"> #include <panel.h>
|
---|
2890 | .
|
---|
2891 | .
|
---|
2892 | .
|
---|
2893 |
|
---|
2894 | compile and link: gcc <program file> -lpanel -lncurses</font>
|
---|
2895 | </pre></td>
|
---|
2896 | </tr>
|
---|
2897 | </table>
|
---|
2898 | <div class="EXAMPLE"><a name="PPASI" id="PPASI"></a>
|
---|
2899 | <p><b>Example 14. Panel basics</b></p>
|
---|
2900 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
2901 | <tr>
|
---|
2902 | <td>
|
---|
2903 | <pre class="PROGRAMLISTING">
|
---|
2904 | <font color="#000000"><span class=
|
---|
2905 | "INLINEMEDIAOBJECT">#include <panel.h>
|
---|
2906 |
|
---|
2907 | int main()
|
---|
2908 | { WINDOW *my_wins[3];
|
---|
2909 | PANEL *my_panels[3];
|
---|
2910 | int lines = 10, cols = 40, y = 2, x = 4, i;
|
---|
2911 |
|
---|
2912 | initscr();
|
---|
2913 | cbreak();
|
---|
2914 | noecho();
|
---|
2915 |
|
---|
2916 | /* Create windows for the panels */
|
---|
2917 | my_wins[0] = newwin(lines, cols, y, x);
|
---|
2918 | my_wins[1] = newwin(lines, cols, y + 1, x + 5);
|
---|
2919 | my_wins[2] = newwin(lines, cols, y + 2, x + 10);
|
---|
2920 |
|
---|
2921 | /*
|
---|
2922 | * Create borders around the windows so that you can see the effect
|
---|
2923 | * of panels
|
---|
2924 | */
|
---|
2925 | for(i = 0; i < 3; ++i)
|
---|
2926 | box(my_wins[i], 0, 0);
|
---|
2927 |
|
---|
2928 | /* Attach a panel to each window */ /* Order is bottom up */
|
---|
2929 | my_panels[0] = new_panel(my_wins[0]); /* Push 0, order: stdscr-0 */
|
---|
2930 | my_panels[1] = new_panel(my_wins[1]); /* Push 1, order: stdscr-0-1 */
|
---|
2931 | my_panels[2] = new_panel(my_wins[2]); /* Push 2, order: stdscr-0-1-2 */
|
---|
2932 |
|
---|
2933 | /* Update the stacking order. 2nd panel will be on top */
|
---|
2934 | update_panels();
|
---|
2935 |
|
---|
2936 | /* Show it on the screen */
|
---|
2937 | doupdate();
|
---|
2938 |
|
---|
2939 | getch();
|
---|
2940 | endwin();
|
---|
2941 | }
|
---|
2942 | </span></font>
|
---|
2943 | </pre></td>
|
---|
2944 | </tr>
|
---|
2945 | </table>
|
---|
2946 | </div>
|
---|
2947 | <p>As you can see, above program follows a simple flow as
|
---|
2948 | explained. The windows are created with newwin() and then they are
|
---|
2949 | attached to panels with new_panel(). As we attach one panel after
|
---|
2950 | another, the stack of panels gets updated. To put them on screen
|
---|
2951 | update_panels() and doupdate() are called.</p>
|
---|
2952 | </div>
|
---|
2953 | <div class="SECT2">
|
---|
2954 | <hr>
|
---|
2955 | <h3 class="SECT2"><a name="PANELBROWSING" id="PANELBROWSING">16.3.
|
---|
2956 | Panel Window Browsing</a></h3>
|
---|
2957 | <p>A slightly complicated example is given below. This program
|
---|
2958 | creates 3 windows which can be cycled through using tab. Have a
|
---|
2959 | look at the code.</p>
|
---|
2960 | <div class="EXAMPLE"><a name="PPABR" id="PPABR"></a>
|
---|
2961 | <p><b>Example 15. Panel Window Browsing Example</b></p>
|
---|
2962 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
2963 | <tr>
|
---|
2964 | <td>
|
---|
2965 | <pre class="PROGRAMLISTING">
|
---|
2966 | <font color="#000000"><span class=
|
---|
2967 | "INLINEMEDIAOBJECT">#include <panel.h>
|
---|
2968 |
|
---|
2969 | #define NLINES 10
|
---|
2970 | #define NCOLS 40
|
---|
2971 |
|
---|
2972 | void init_wins(WINDOW **wins, int n);
|
---|
2973 | void win_show(WINDOW *win, char *label, int label_color);
|
---|
2974 | void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color);
|
---|
2975 |
|
---|
2976 | int main()
|
---|
2977 | { WINDOW *my_wins[3];
|
---|
2978 | PANEL *my_panels[3];
|
---|
2979 | PANEL *top;
|
---|
2980 | int ch;
|
---|
2981 |
|
---|
2982 | /* Initialize curses */
|
---|
2983 | initscr();
|
---|
2984 | start_color();
|
---|
2985 | cbreak();
|
---|
2986 | noecho();
|
---|
2987 | keypad(stdscr, TRUE);
|
---|
2988 |
|
---|
2989 | /* Initialize all the colors */
|
---|
2990 | init_pair(1, COLOR_RED, COLOR_BLACK);
|
---|
2991 | init_pair(2, COLOR_GREEN, COLOR_BLACK);
|
---|
2992 | init_pair(3, COLOR_BLUE, COLOR_BLACK);
|
---|
2993 | init_pair(4, COLOR_CYAN, COLOR_BLACK);
|
---|
2994 |
|
---|
2995 | init_wins(my_wins, 3);
|
---|
2996 |
|
---|
2997 | /* Attach a panel to each window */ /* Order is bottom up */
|
---|
2998 | my_panels[0] = new_panel(my_wins[0]); /* Push 0, order: stdscr-0 */
|
---|
2999 | my_panels[1] = new_panel(my_wins[1]); /* Push 1, order: stdscr-0-1 */
|
---|
3000 | my_panels[2] = new_panel(my_wins[2]); /* Push 2, order: stdscr-0-1-2 */
|
---|
3001 |
|
---|
3002 | /* Set up the user pointers to the next panel */
|
---|
3003 | set_panel_userptr(my_panels[0], my_panels[1]);
|
---|
3004 | set_panel_userptr(my_panels[1], my_panels[2]);
|
---|
3005 | set_panel_userptr(my_panels[2], my_panels[0]);
|
---|
3006 |
|
---|
3007 | /* Update the stacking order. 2nd panel will be on top */
|
---|
3008 | update_panels();
|
---|
3009 |
|
---|
3010 | /* Show it on the screen */
|
---|
3011 | attron(COLOR_PAIR(4));
|
---|
3012 | mvprintw(LINES - 2, 0, "Use tab to browse through the windows (F1 to Exit)");
|
---|
3013 | attroff(COLOR_PAIR(4));
|
---|
3014 | doupdate();
|
---|
3015 |
|
---|
3016 | top = my_panels[2];
|
---|
3017 | while((ch = getch()) != KEY_F(1))
|
---|
3018 | { switch(ch)
|
---|
3019 | { case 9:
|
---|
3020 | top = (PANEL *)panel_userptr(top);
|
---|
3021 | top_panel(top);
|
---|
3022 | break;
|
---|
3023 | }
|
---|
3024 | update_panels();
|
---|
3025 | doupdate();
|
---|
3026 | }
|
---|
3027 | endwin();
|
---|
3028 | return 0;
|
---|
3029 | }
|
---|
3030 |
|
---|
3031 | /* Put all the windows */
|
---|
3032 | void init_wins(WINDOW **wins, int n)
|
---|
3033 | { int x, y, i;
|
---|
3034 | char label[80];
|
---|
3035 |
|
---|
3036 | y = 2;
|
---|
3037 | x = 10;
|
---|
3038 | for(i = 0; i < n; ++i)
|
---|
3039 | { wins[i] = newwin(NLINES, NCOLS, y, x);
|
---|
3040 | sprintf(label, "Window Number %d", i + 1);
|
---|
3041 | win_show(wins[i], label, i + 1);
|
---|
3042 | y += 3;
|
---|
3043 | x += 7;
|
---|
3044 | }
|
---|
3045 | }
|
---|
3046 |
|
---|
3047 | /* Show the window with a border and a label */
|
---|
3048 | void win_show(WINDOW *win, char *label, int label_color)
|
---|
3049 | { int startx, starty, height, width;
|
---|
3050 |
|
---|
3051 | getbegyx(win, starty, startx);
|
---|
3052 | getmaxyx(win, height, width);
|
---|
3053 |
|
---|
3054 | box(win, 0, 0);
|
---|
3055 | mvwaddch(win, 2, 0, ACS_LTEE);
|
---|
3056 | mvwhline(win, 2, 1, ACS_HLINE, width - 2);
|
---|
3057 | mvwaddch(win, 2, width - 1, ACS_RTEE);
|
---|
3058 |
|
---|
3059 | print_in_middle(win, 1, 0, width, label, COLOR_PAIR(label_color));
|
---|
3060 | }
|
---|
3061 |
|
---|
3062 | void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color)
|
---|
3063 | { int length, x, y;
|
---|
3064 | float temp;
|
---|
3065 |
|
---|
3066 | if(win == NULL)
|
---|
3067 | win = stdscr;
|
---|
3068 | getyx(win, y, x);
|
---|
3069 | if(startx != 0)
|
---|
3070 | x = startx;
|
---|
3071 | if(starty != 0)
|
---|
3072 | y = starty;
|
---|
3073 | if(width == 0)
|
---|
3074 | width = 80;
|
---|
3075 |
|
---|
3076 | length = strlen(string);
|
---|
3077 | temp = (width - length)/ 2;
|
---|
3078 | x = startx + (int)temp;
|
---|
3079 | wattron(win, color);
|
---|
3080 | mvwprintw(win, y, x, "%s", string);
|
---|
3081 | wattroff(win, color);
|
---|
3082 | refresh();
|
---|
3083 | }</span></font>
|
---|
3084 | </pre></td>
|
---|
3085 | </tr>
|
---|
3086 | </table>
|
---|
3087 | </div>
|
---|
3088 | </div>
|
---|
3089 | <div class="SECT2">
|
---|
3090 | <hr>
|
---|
3091 | <h3 class="SECT2"><a name="USERPTRUSING" id="USERPTRUSING">16.4.
|
---|
3092 | Using User Pointers</a></h3>
|
---|
3093 | <p>In the above example I used user pointers to find out the next
|
---|
3094 | window in the cycle. We can attach custom information to the panel
|
---|
3095 | by specifying a user pointer, which can point to any information
|
---|
3096 | you want to store. In this case I stored the pointer to the next
|
---|
3097 | panel in the cycle. User pointer for a panel can be set with the
|
---|
3098 | function <var class="LITERAL">set_panel_userptr()</var>. It can be
|
---|
3099 | accessed using the function <var class=
|
---|
3100 | "LITERAL">panel_userptr()</var> which will return the user pointer
|
---|
3101 | for the panel given as argument. After finding the next panel in
|
---|
3102 | the cycle It's brought to the top by the function top_panel(). This
|
---|
3103 | function brings the panel given as argument to the top of the panel
|
---|
3104 | stack.</p>
|
---|
3105 | </div>
|
---|
3106 | <div class="SECT2">
|
---|
3107 | <hr>
|
---|
3108 | <h3 class="SECT2"><a name="PANELMOVERESIZE" id=
|
---|
3109 | "PANELMOVERESIZE">16.5. Moving and Resizing Panels</a></h3>
|
---|
3110 | <p>The function <var class="LITERAL">move_panel()</var> can be used
|
---|
3111 | to move a panel to the desired location. It does not change the
|
---|
3112 | position of the panel in the stack. Make sure that you use
|
---|
3113 | move_panel() instead mvwin() on the window associated with the
|
---|
3114 | panel.</p>
|
---|
3115 | <p>Resizing a panel is slightly complex. There is no straight
|
---|
3116 | forward function just to resize the window associated with a panel.
|
---|
3117 | A solution to resize a panel is to create a new window with the
|
---|
3118 | desired sizes, change the window associated with the panel using
|
---|
3119 | replace_panel(). Don't forget to delete the old window. The window
|
---|
3120 | associated with a panel can be found by using the function
|
---|
3121 | panel_window().</p>
|
---|
3122 | <p>The following program shows these concepts, in supposedly simple
|
---|
3123 | program. You can cycle through the window with <TAB> as
|
---|
3124 | usual. To resize or move the active panel press 'r' for resize 'm'
|
---|
3125 | for moving. Then use arrow keys to resize or move it to the desired
|
---|
3126 | way and press enter to end your resizing or moving. This example
|
---|
3127 | makes use of user data to get the required data to do the
|
---|
3128 | operations.</p>
|
---|
3129 | <div class="EXAMPLE"><a name="PPARE" id="PPARE"></a>
|
---|
3130 | <p><b>Example 16. Panel Moving and Resizing example</b></p>
|
---|
3131 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
3132 | <tr>
|
---|
3133 | <td>
|
---|
3134 | <pre class="PROGRAMLISTING">
|
---|
3135 | <font color="#000000"><span class=
|
---|
3136 | "INLINEMEDIAOBJECT">#include <panel.h>
|
---|
3137 |
|
---|
3138 | typedef struct _PANEL_DATA {
|
---|
3139 | int x, y, w, h;
|
---|
3140 | char label[80];
|
---|
3141 | int label_color;
|
---|
3142 | PANEL *next;
|
---|
3143 | }PANEL_DATA;
|
---|
3144 |
|
---|
3145 | #define NLINES 10
|
---|
3146 | #define NCOLS 40
|
---|
3147 |
|
---|
3148 | void init_wins(WINDOW **wins, int n);
|
---|
3149 | void win_show(WINDOW *win, char *label, int label_color);
|
---|
3150 | void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color);
|
---|
3151 | void set_user_ptrs(PANEL **panels, int n);
|
---|
3152 |
|
---|
3153 | int main()
|
---|
3154 | { WINDOW *my_wins[3];
|
---|
3155 | PANEL *my_panels[3];
|
---|
3156 | PANEL_DATA *top;
|
---|
3157 | PANEL *stack_top;
|
---|
3158 | WINDOW *temp_win, *old_win;
|
---|
3159 | int ch;
|
---|
3160 | int newx, newy, neww, newh;
|
---|
3161 | int size = FALSE, move = FALSE;
|
---|
3162 |
|
---|
3163 | /* Initialize curses */
|
---|
3164 | initscr();
|
---|
3165 | start_color();
|
---|
3166 | cbreak();
|
---|
3167 | noecho();
|
---|
3168 | keypad(stdscr, TRUE);
|
---|
3169 |
|
---|
3170 | /* Initialize all the colors */
|
---|
3171 | init_pair(1, COLOR_RED, COLOR_BLACK);
|
---|
3172 | init_pair(2, COLOR_GREEN, COLOR_BLACK);
|
---|
3173 | init_pair(3, COLOR_BLUE, COLOR_BLACK);
|
---|
3174 | init_pair(4, COLOR_CYAN, COLOR_BLACK);
|
---|
3175 |
|
---|
3176 | init_wins(my_wins, 3);
|
---|
3177 |
|
---|
3178 | /* Attach a panel to each window */ /* Order is bottom up */
|
---|
3179 | my_panels[0] = new_panel(my_wins[0]); /* Push 0, order: stdscr-0 */
|
---|
3180 | my_panels[1] = new_panel(my_wins[1]); /* Push 1, order: stdscr-0-1 */
|
---|
3181 | my_panels[2] = new_panel(my_wins[2]); /* Push 2, order: stdscr-0-1-2 */
|
---|
3182 |
|
---|
3183 | set_user_ptrs(my_panels, 3);
|
---|
3184 | /* Update the stacking order. 2nd panel will be on top */
|
---|
3185 | update_panels();
|
---|
3186 |
|
---|
3187 | /* Show it on the screen */
|
---|
3188 | attron(COLOR_PAIR(4));
|
---|
3189 | mvprintw(LINES - 3, 0, "Use 'm' for moving, 'r' for resizing");
|
---|
3190 | mvprintw(LINES - 2, 0, "Use tab to browse through the windows (F1 to Exit)");
|
---|
3191 | attroff(COLOR_PAIR(4));
|
---|
3192 | doupdate();
|
---|
3193 |
|
---|
3194 | stack_top = my_panels[2];
|
---|
3195 | top = (PANEL_DATA *)panel_userptr(stack_top);
|
---|
3196 | newx = top->x;
|
---|
3197 | newy = top->y;
|
---|
3198 | neww = top->w;
|
---|
3199 | newh = top->h;
|
---|
3200 | while((ch = getch()) != KEY_F(1))
|
---|
3201 | { switch(ch)
|
---|
3202 | { case 9: /* Tab */
|
---|
3203 | top = (PANEL_DATA *)panel_userptr(stack_top);
|
---|
3204 | top_panel(top->next);
|
---|
3205 | stack_top = top->next;
|
---|
3206 | top = (PANEL_DATA *)panel_userptr(stack_top);
|
---|
3207 | newx = top->x;
|
---|
3208 | newy = top->y;
|
---|
3209 | neww = top->w;
|
---|
3210 | newh = top->h;
|
---|
3211 | break;
|
---|
3212 | case 'r': /* Re-Size*/
|
---|
3213 | size = TRUE;
|
---|
3214 | attron(COLOR_PAIR(4));
|
---|
3215 | mvprintw(LINES - 4, 0, "Entered Resizing :Use Arrow Keys to resize and press <ENTER> to end resizing");
|
---|
3216 | refresh();
|
---|
3217 | attroff(COLOR_PAIR(4));
|
---|
3218 | break;
|
---|
3219 | case 'm': /* Move */
|
---|
3220 | attron(COLOR_PAIR(4));
|
---|
3221 | mvprintw(LINES - 4, 0, "Entered Moving: Use Arrow Keys to Move and press <ENTER> to end moving");
|
---|
3222 | refresh();
|
---|
3223 | attroff(COLOR_PAIR(4));
|
---|
3224 | move = TRUE;
|
---|
3225 | break;
|
---|
3226 | case KEY_LEFT:
|
---|
3227 | if(size == TRUE)
|
---|
3228 | { --newx;
|
---|
3229 | ++neww;
|
---|
3230 | }
|
---|
3231 | if(move == TRUE)
|
---|
3232 | --newx;
|
---|
3233 | break;
|
---|
3234 | case KEY_RIGHT:
|
---|
3235 | if(size == TRUE)
|
---|
3236 | { ++newx;
|
---|
3237 | --neww;
|
---|
3238 | }
|
---|
3239 | if(move == TRUE)
|
---|
3240 | ++newx;
|
---|
3241 | break;
|
---|
3242 | case KEY_UP:
|
---|
3243 | if(size == TRUE)
|
---|
3244 | { --newy;
|
---|
3245 | ++newh;
|
---|
3246 | }
|
---|
3247 | if(move == TRUE)
|
---|
3248 | --newy;
|
---|
3249 | break;
|
---|
3250 | case KEY_DOWN:
|
---|
3251 | if(size == TRUE)
|
---|
3252 | { ++newy;
|
---|
3253 | --newh;
|
---|
3254 | }
|
---|
3255 | if(move == TRUE)
|
---|
3256 | ++newy;
|
---|
3257 | break;
|
---|
3258 | case 10: /* Enter */
|
---|
3259 | move(LINES - 4, 0);
|
---|
3260 | clrtoeol();
|
---|
3261 | refresh();
|
---|
3262 | if(size == TRUE)
|
---|
3263 | { old_win = panel_window(stack_top);
|
---|
3264 | temp_win = newwin(newh, neww, newy, newx);
|
---|
3265 | replace_panel(stack_top, temp_win);
|
---|
3266 | win_show(temp_win, top->label, top->label_color);
|
---|
3267 | delwin(old_win);
|
---|
3268 | size = FALSE;
|
---|
3269 | }
|
---|
3270 | if(move == TRUE)
|
---|
3271 | { move_panel(stack_top, newy, newx);
|
---|
3272 | move = FALSE;
|
---|
3273 | }
|
---|
3274 | break;
|
---|
3275 |
|
---|
3276 | }
|
---|
3277 | attron(COLOR_PAIR(4));
|
---|
3278 | mvprintw(LINES - 3, 0, "Use 'm' for moving, 'r' for resizing");
|
---|
3279 | mvprintw(LINES - 2, 0, "Use tab to browse through the windows (F1 to Exit)");
|
---|
3280 | attroff(COLOR_PAIR(4));
|
---|
3281 | refresh();
|
---|
3282 | update_panels();
|
---|
3283 | doupdate();
|
---|
3284 | }
|
---|
3285 | endwin();
|
---|
3286 | return 0;
|
---|
3287 | }
|
---|
3288 |
|
---|
3289 | /* Put all the windows */
|
---|
3290 | void init_wins(WINDOW **wins, int n)
|
---|
3291 | { int x, y, i;
|
---|
3292 | char label[80];
|
---|
3293 |
|
---|
3294 | y = 2;
|
---|
3295 | x = 10;
|
---|
3296 | for(i = 0; i < n; ++i)
|
---|
3297 | { wins[i] = newwin(NLINES, NCOLS, y, x);
|
---|
3298 | sprintf(label, "Window Number %d", i + 1);
|
---|
3299 | win_show(wins[i], label, i + 1);
|
---|
3300 | y += 3;
|
---|
3301 | x += 7;
|
---|
3302 | }
|
---|
3303 | }
|
---|
3304 |
|
---|
3305 | /* Set the PANEL_DATA structures for individual panels */
|
---|
3306 | void set_user_ptrs(PANEL **panels, int n)
|
---|
3307 | { PANEL_DATA *ptrs;
|
---|
3308 | WINDOW *win;
|
---|
3309 | int x, y, w, h, i;
|
---|
3310 | char temp[80];
|
---|
3311 |
|
---|
3312 | ptrs = (PANEL_DATA *)calloc(n, sizeof(PANEL_DATA));
|
---|
3313 |
|
---|
3314 | for(i = 0;i < n; ++i)
|
---|
3315 | { win = panel_window(panels[i]);
|
---|
3316 | getbegyx(win, y, x);
|
---|
3317 | getmaxyx(win, h, w);
|
---|
3318 | ptrs[i].x = x;
|
---|
3319 | ptrs[i].y = y;
|
---|
3320 | ptrs[i].w = w;
|
---|
3321 | ptrs[i].h = h;
|
---|
3322 | sprintf(temp, "Window Number %d", i + 1);
|
---|
3323 | strcpy(ptrs[i].label, temp);
|
---|
3324 | ptrs[i].label_color = i + 1;
|
---|
3325 | if(i + 1 == n)
|
---|
3326 | ptrs[i].next = panels[0];
|
---|
3327 | else
|
---|
3328 | ptrs[i].next = panels[i + 1];
|
---|
3329 | set_panel_userptr(panels[i], &ptrs[i]);
|
---|
3330 | }
|
---|
3331 | }
|
---|
3332 |
|
---|
3333 | /* Show the window with a border and a label */
|
---|
3334 | void win_show(WINDOW *win, char *label, int label_color)
|
---|
3335 | { int startx, starty, height, width;
|
---|
3336 |
|
---|
3337 | getbegyx(win, starty, startx);
|
---|
3338 | getmaxyx(win, height, width);
|
---|
3339 |
|
---|
3340 | box(win, 0, 0);
|
---|
3341 | mvwaddch(win, 2, 0, ACS_LTEE);
|
---|
3342 | mvwhline(win, 2, 1, ACS_HLINE, width - 2);
|
---|
3343 | mvwaddch(win, 2, width - 1, ACS_RTEE);
|
---|
3344 |
|
---|
3345 | print_in_middle(win, 1, 0, width, label, COLOR_PAIR(label_color));
|
---|
3346 | }
|
---|
3347 |
|
---|
3348 | void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color)
|
---|
3349 | { int length, x, y;
|
---|
3350 | float temp;
|
---|
3351 |
|
---|
3352 | if(win == NULL)
|
---|
3353 | win = stdscr;
|
---|
3354 | getyx(win, y, x);
|
---|
3355 | if(startx != 0)
|
---|
3356 | x = startx;
|
---|
3357 | if(starty != 0)
|
---|
3358 | y = starty;
|
---|
3359 | if(width == 0)
|
---|
3360 | width = 80;
|
---|
3361 |
|
---|
3362 | length = strlen(string);
|
---|
3363 | temp = (width - length)/ 2;
|
---|
3364 | x = startx + (int)temp;
|
---|
3365 | wattron(win, color);
|
---|
3366 | mvwprintw(win, y, x, "%s", string);
|
---|
3367 | wattroff(win, color);
|
---|
3368 | refresh();
|
---|
3369 | }</span></font>
|
---|
3370 | </pre></td>
|
---|
3371 | </tr>
|
---|
3372 | </table>
|
---|
3373 | </div>
|
---|
3374 | <p>Concentrate on the main while loop. Once it finds out the type
|
---|
3375 | of key pressed, it takes appropriate action. If 'r' is pressed
|
---|
3376 | resizing mode is started. After this the new sizes are updated as
|
---|
3377 | the user presses the arrow keys. When the user presses
|
---|
3378 | <ENTER> present selection ends and panel is resized by using
|
---|
3379 | the concept explained. While in resizing mode the program doesn't
|
---|
3380 | show how the window is getting resized. It's left as an exercise to
|
---|
3381 | the reader to print a dotted border while it gets resized to a new
|
---|
3382 | position.</p>
|
---|
3383 | <p>When the user presses 'm' the move mode starts. This is a bit
|
---|
3384 | simpler than resizing. As the arrow keys are pressed the new
|
---|
3385 | position is updated and pressing of <ENTER> causes the panel
|
---|
3386 | to be moved by calling the function move_panel().</p>
|
---|
3387 | <p>In this program the user data which is represented as
|
---|
3388 | PANEL_DATA, plays very important role in finding the associated
|
---|
3389 | information with a panel. As written in the comments, the
|
---|
3390 | PANEL_DATA stores the panel sizes, label, label color and a pointer
|
---|
3391 | to the next panel in the cycle.</p>
|
---|
3392 | </div>
|
---|
3393 | <div class="SECT2">
|
---|
3394 | <hr>
|
---|
3395 | <h3 class="SECT2"><a name="PANELSHOWHIDE" id="PANELSHOWHIDE">16.6.
|
---|
3396 | Hiding and Showing Panels</a></h3>
|
---|
3397 | <p>A Panel can be hidden by using the function hide_panel(). This
|
---|
3398 | function merely removes it form the stack of panels, thus hiding it
|
---|
3399 | on the screen once you do update_panels() and doupdate(). It
|
---|
3400 | doesn't destroy the PANEL structure associated with the hidden
|
---|
3401 | panel. It can be shown again by using the show_panel()
|
---|
3402 | function.</p>
|
---|
3403 | <p>The following program shows the hiding of panels. Press 'a' or
|
---|
3404 | 'b' or 'c' to show or hide first, second and third windows
|
---|
3405 | respectively. It uses a user data with a small variable hide, which
|
---|
3406 | keeps track of whether the window is hidden or not. For some reason
|
---|
3407 | the function <var class="LITERAL">panel_hidden()</var> which tells
|
---|
3408 | whether a panel is hidden or not is not working. A bug report was
|
---|
3409 | also presented by Michael Andres <a href=
|
---|
3410 | "http://www.geocrawler.com/archives/3/344/1999/9/0/2643549/"
|
---|
3411 | target="_top">here</a></p>
|
---|
3412 | <div class="EXAMPLE"><a name="PPAHI" id="PPAHI"></a>
|
---|
3413 | <p><b>Example 17. Panel Hiding and Showing example</b></p>
|
---|
3414 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
3415 | <tr>
|
---|
3416 | <td>
|
---|
3417 | <pre class="PROGRAMLISTING">
|
---|
3418 | <font color="#000000"><span class=
|
---|
3419 | "INLINEMEDIAOBJECT">#include <panel.h>
|
---|
3420 |
|
---|
3421 | typedef struct _PANEL_DATA {
|
---|
3422 | int hide; /* TRUE if panel is hidden */
|
---|
3423 | }PANEL_DATA;
|
---|
3424 |
|
---|
3425 | #define NLINES 10
|
---|
3426 | #define NCOLS 40
|
---|
3427 |
|
---|
3428 | void init_wins(WINDOW **wins, int n);
|
---|
3429 | void win_show(WINDOW *win, char *label, int label_color);
|
---|
3430 | void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color);
|
---|
3431 |
|
---|
3432 | int main()
|
---|
3433 | { WINDOW *my_wins[3];
|
---|
3434 | PANEL *my_panels[3];
|
---|
3435 | PANEL_DATA panel_datas[3];
|
---|
3436 | PANEL_DATA *temp;
|
---|
3437 | int ch;
|
---|
3438 |
|
---|
3439 | /* Initialize curses */
|
---|
3440 | initscr();
|
---|
3441 | start_color();
|
---|
3442 | cbreak();
|
---|
3443 | noecho();
|
---|
3444 | keypad(stdscr, TRUE);
|
---|
3445 |
|
---|
3446 | /* Initialize all the colors */
|
---|
3447 | init_pair(1, COLOR_RED, COLOR_BLACK);
|
---|
3448 | init_pair(2, COLOR_GREEN, COLOR_BLACK);
|
---|
3449 | init_pair(3, COLOR_BLUE, COLOR_BLACK);
|
---|
3450 | init_pair(4, COLOR_CYAN, COLOR_BLACK);
|
---|
3451 |
|
---|
3452 | init_wins(my_wins, 3);
|
---|
3453 |
|
---|
3454 | /* Attach a panel to each window */ /* Order is bottom up */
|
---|
3455 | my_panels[0] = new_panel(my_wins[0]); /* Push 0, order: stdscr-0 */
|
---|
3456 | my_panels[1] = new_panel(my_wins[1]); /* Push 1, order: stdscr-0-1 */
|
---|
3457 | my_panels[2] = new_panel(my_wins[2]); /* Push 2, order: stdscr-0-1-2 */
|
---|
3458 |
|
---|
3459 | /* Initialize panel datas saying that nothing is hidden */
|
---|
3460 | panel_datas[0].hide = FALSE;
|
---|
3461 | panel_datas[1].hide = FALSE;
|
---|
3462 | panel_datas[2].hide = FALSE;
|
---|
3463 |
|
---|
3464 | set_panel_userptr(my_panels[0], &panel_datas[0]);
|
---|
3465 | set_panel_userptr(my_panels[1], &panel_datas[1]);
|
---|
3466 | set_panel_userptr(my_panels[2], &panel_datas[2]);
|
---|
3467 |
|
---|
3468 | /* Update the stacking order. 2nd panel will be on top */
|
---|
3469 | update_panels();
|
---|
3470 |
|
---|
3471 | /* Show it on the screen */
|
---|
3472 | attron(COLOR_PAIR(4));
|
---|
3473 | mvprintw(LINES - 3, 0, "Show or Hide a window with 'a'(first window) 'b'(Second Window) 'c'(Third Window)");
|
---|
3474 | mvprintw(LINES - 2, 0, "F1 to Exit");
|
---|
3475 |
|
---|
3476 | attroff(COLOR_PAIR(4));
|
---|
3477 | doupdate();
|
---|
3478 |
|
---|
3479 | while((ch = getch()) != KEY_F(1))
|
---|
3480 | { switch(ch)
|
---|
3481 | { case 'a':
|
---|
3482 | temp = (PANEL_DATA *)panel_userptr(my_panels[0]);
|
---|
3483 | if(temp->hide == FALSE)
|
---|
3484 | { hide_panel(my_panels[0]);
|
---|
3485 | temp->hide = TRUE;
|
---|
3486 | }
|
---|
3487 | else
|
---|
3488 | { show_panel(my_panels[0]);
|
---|
3489 | temp->hide = FALSE;
|
---|
3490 | }
|
---|
3491 | break;
|
---|
3492 | case 'b':
|
---|
3493 | temp = (PANEL_DATA *)panel_userptr(my_panels[1]);
|
---|
3494 | if(temp->hide == FALSE)
|
---|
3495 | { hide_panel(my_panels[1]);
|
---|
3496 | temp->hide = TRUE;
|
---|
3497 | }
|
---|
3498 | else
|
---|
3499 | { show_panel(my_panels[1]);
|
---|
3500 | temp->hide = FALSE;
|
---|
3501 | }
|
---|
3502 | break;
|
---|
3503 | case 'c':
|
---|
3504 | temp = (PANEL_DATA *)panel_userptr(my_panels[2]);
|
---|
3505 | if(temp->hide == FALSE)
|
---|
3506 | { hide_panel(my_panels[2]);
|
---|
3507 | temp->hide = TRUE;
|
---|
3508 | }
|
---|
3509 | else
|
---|
3510 | { show_panel(my_panels[2]);
|
---|
3511 | temp->hide = FALSE;
|
---|
3512 | }
|
---|
3513 | break;
|
---|
3514 | }
|
---|
3515 | update_panels();
|
---|
3516 | doupdate();
|
---|
3517 | }
|
---|
3518 | endwin();
|
---|
3519 | return 0;
|
---|
3520 | }
|
---|
3521 |
|
---|
3522 | /* Put all the windows */
|
---|
3523 | void init_wins(WINDOW **wins, int n)
|
---|
3524 | { int x, y, i;
|
---|
3525 | char label[80];
|
---|
3526 |
|
---|
3527 | y = 2;
|
---|
3528 | x = 10;
|
---|
3529 | for(i = 0; i < n; ++i)
|
---|
3530 | { wins[i] = newwin(NLINES, NCOLS, y, x);
|
---|
3531 | sprintf(label, "Window Number %d", i + 1);
|
---|
3532 | win_show(wins[i], label, i + 1);
|
---|
3533 | y += 3;
|
---|
3534 | x += 7;
|
---|
3535 | }
|
---|
3536 | }
|
---|
3537 |
|
---|
3538 | /* Show the window with a border and a label */
|
---|
3539 | void win_show(WINDOW *win, char *label, int label_color)
|
---|
3540 | { int startx, starty, height, width;
|
---|
3541 |
|
---|
3542 | getbegyx(win, starty, startx);
|
---|
3543 | getmaxyx(win, height, width);
|
---|
3544 |
|
---|
3545 | box(win, 0, 0);
|
---|
3546 | mvwaddch(win, 2, 0, ACS_LTEE);
|
---|
3547 | mvwhline(win, 2, 1, ACS_HLINE, width - 2);
|
---|
3548 | mvwaddch(win, 2, width - 1, ACS_RTEE);
|
---|
3549 |
|
---|
3550 | print_in_middle(win, 1, 0, width, label, COLOR_PAIR(label_color));
|
---|
3551 | }
|
---|
3552 |
|
---|
3553 | void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color)
|
---|
3554 | { int length, x, y;
|
---|
3555 | float temp;
|
---|
3556 |
|
---|
3557 | if(win == NULL)
|
---|
3558 | win = stdscr;
|
---|
3559 | getyx(win, y, x);
|
---|
3560 | if(startx != 0)
|
---|
3561 | x = startx;
|
---|
3562 | if(starty != 0)
|
---|
3563 | y = starty;
|
---|
3564 | if(width == 0)
|
---|
3565 | width = 80;
|
---|
3566 |
|
---|
3567 | length = strlen(string);
|
---|
3568 | temp = (width - length)/ 2;
|
---|
3569 | x = startx + (int)temp;
|
---|
3570 | wattron(win, color);
|
---|
3571 | mvwprintw(win, y, x, "%s", string);
|
---|
3572 | wattroff(win, color);
|
---|
3573 | refresh();
|
---|
3574 | }</span></font>
|
---|
3575 | </pre></td>
|
---|
3576 | </tr>
|
---|
3577 | </table>
|
---|
3578 | </div>
|
---|
3579 | </div>
|
---|
3580 | <div class="SECT2">
|
---|
3581 | <hr>
|
---|
3582 | <h3 class="SECT2"><a name="PANELABOVE" id="PANELABOVE">16.7.
|
---|
3583 | panel_above() and panel_below() Functions</a></h3>
|
---|
3584 | <p>The functions <var class="LITERAL">panel_above()</var> and
|
---|
3585 | <var class="LITERAL">panel_below()</var> can be used to find out
|
---|
3586 | the panel above and below a panel. If the argument to these
|
---|
3587 | functions is NULL, then they return a pointer to bottom panel and
|
---|
3588 | top panel respectively.</p>
|
---|
3589 | </div>
|
---|
3590 | </div>
|
---|
3591 | <div class="SECT1">
|
---|
3592 | <hr>
|
---|
3593 | <h2 class="SECT1"><a name="MENUS" id="MENUS">17. Menus
|
---|
3594 | Library</a></h2>
|
---|
3595 | <p>The menus library provides a nice extension to basic curses,
|
---|
3596 | through which you can create menus. It provides a set of functions
|
---|
3597 | to create menus. But they have to be customized to give a nicer
|
---|
3598 | look, with colors etc. Let's get into the details.</p>
|
---|
3599 | <p>A menu is a screen display that assists the user to choose some
|
---|
3600 | subset of a given set of items. To put it simple, a menu is a
|
---|
3601 | collection of items from which one or more items can be chosen.
|
---|
3602 | Some readers might not be aware of multiple item selection
|
---|
3603 | capability. Menu library provides functionality to write menus from
|
---|
3604 | which the user can chose more than one item as the preferred
|
---|
3605 | choice. This is dealt with in a later section. Now it is time for
|
---|
3606 | some rudiments.</p>
|
---|
3607 | <div class="SECT2">
|
---|
3608 | <hr>
|
---|
3609 | <h3 class="SECT2"><a name="MENUBASICS" id="MENUBASICS">17.1. The
|
---|
3610 | Basics</a></h3>
|
---|
3611 | <p>To create menus, you first create items, and then post the menu
|
---|
3612 | to the display. After that, all the processing of user responses is
|
---|
3613 | done in an elegant function menu_driver() which is the work horse
|
---|
3614 | of any menu program.</p>
|
---|
3615 | <p>The general flow of control of a menu program looks like
|
---|
3616 | this.</p>
|
---|
3617 | <ol type="1">
|
---|
3618 | <li>
|
---|
3619 | <p>Initialize curses</p>
|
---|
3620 | </li>
|
---|
3621 | <li>
|
---|
3622 | <p>Create items using new_item(). You can specify a name and
|
---|
3623 | description for the items.</p>
|
---|
3624 | </li>
|
---|
3625 | <li>
|
---|
3626 | <p>Create the menu with new_menu() by specifying the items to be
|
---|
3627 | attached with.</p>
|
---|
3628 | </li>
|
---|
3629 | <li>
|
---|
3630 | <p>Post the menu with menu_post() and refresh the screen.</p>
|
---|
3631 | </li>
|
---|
3632 | <li>
|
---|
3633 | <p>Process the user requests with a loop and do necessary updates
|
---|
3634 | to menu with menu_driver.</p>
|
---|
3635 | </li>
|
---|
3636 | <li>
|
---|
3637 | <p>Unpost the menu with menu_unpost()</p>
|
---|
3638 | </li>
|
---|
3639 | <li>
|
---|
3640 | <p>Free the memory allocated to menu by free_menu()</p>
|
---|
3641 | </li>
|
---|
3642 | <li>
|
---|
3643 | <p>Free the memory allocated to the items with free_item()</p>
|
---|
3644 | </li>
|
---|
3645 | <li>
|
---|
3646 | <p>End curses</p>
|
---|
3647 | </li>
|
---|
3648 | </ol>
|
---|
3649 | <p>Let's see a program which prints a simple menu and updates the
|
---|
3650 | current selection with up, down arrows.</p>
|
---|
3651 | </div>
|
---|
3652 | <div class="SECT2">
|
---|
3653 | <hr>
|
---|
3654 | <h3 class="SECT2"><a name="COMPILEMENUS" id="COMPILEMENUS">17.2.
|
---|
3655 | Compiling With the Menu Library</a></h3>
|
---|
3656 | <p>To use menu library functions, you have to include menu.h and to
|
---|
3657 | link the program with menu library the flag -lmenu should be added
|
---|
3658 | along with -lncurses in that order.</p>
|
---|
3659 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
3660 | <tr>
|
---|
3661 | <td>
|
---|
3662 | <pre class="PROGRAMLISTING">
|
---|
3663 | <font color="#000000"> #include <menu.h>
|
---|
3664 | .
|
---|
3665 | .
|
---|
3666 | .
|
---|
3667 |
|
---|
3668 | compile and link: gcc <program file> -lmenu -lncurses</font>
|
---|
3669 | </pre></td>
|
---|
3670 | </tr>
|
---|
3671 | </table>
|
---|
3672 | <div class="EXAMPLE"><a name="MMESI" id="MMESI"></a>
|
---|
3673 | <p><b>Example 18. Menu Basics</b></p>
|
---|
3674 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
3675 | <tr>
|
---|
3676 | <td>
|
---|
3677 | <pre class="PROGRAMLISTING">
|
---|
3678 | <font color="#000000"><span class=
|
---|
3679 | "INLINEMEDIAOBJECT">#include <curses.h>
|
---|
3680 | #include <menu.h>
|
---|
3681 |
|
---|
3682 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
---|
3683 | #define CTRLD 4
|
---|
3684 |
|
---|
3685 | char *choices[] = {
|
---|
3686 | "Choice 1",
|
---|
3687 | "Choice 2",
|
---|
3688 | "Choice 3",
|
---|
3689 | "Choice 4",
|
---|
3690 | "Exit",
|
---|
3691 | };
|
---|
3692 |
|
---|
3693 | int main()
|
---|
3694 | { ITEM **my_items;
|
---|
3695 | int c;
|
---|
3696 | MENU *my_menu;
|
---|
3697 | int n_choices, i;
|
---|
3698 | ITEM *cur_item;
|
---|
3699 |
|
---|
3700 |
|
---|
3701 | initscr();
|
---|
3702 | cbreak();
|
---|
3703 | noecho();
|
---|
3704 | keypad(stdscr, TRUE);
|
---|
3705 |
|
---|
3706 | n_choices = ARRAY_SIZE(choices);
|
---|
3707 | my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *));
|
---|
3708 |
|
---|
3709 | for(i = 0; i < n_choices; ++i)
|
---|
3710 | my_items[i] = new_item(choices[i], choices[i]);
|
---|
3711 | my_items[n_choices] = (ITEM *)NULL;
|
---|
3712 |
|
---|
3713 | my_menu = new_menu((ITEM **)my_items);
|
---|
3714 | mvprintw(LINES - 2, 0, "F1 to Exit");
|
---|
3715 | post_menu(my_menu);
|
---|
3716 | refresh();
|
---|
3717 |
|
---|
3718 | while((c = getch()) != KEY_F(1))
|
---|
3719 | { switch(c)
|
---|
3720 | { case KEY_DOWN:
|
---|
3721 | menu_driver(my_menu, REQ_DOWN_ITEM);
|
---|
3722 | break;
|
---|
3723 | case KEY_UP:
|
---|
3724 | menu_driver(my_menu, REQ_UP_ITEM);
|
---|
3725 | break;
|
---|
3726 | }
|
---|
3727 | }
|
---|
3728 |
|
---|
3729 | free_item(my_items[0]);
|
---|
3730 | free_item(my_items[1]);
|
---|
3731 | free_menu(my_menu);
|
---|
3732 | endwin();
|
---|
3733 | }
|
---|
3734 | </span></font>
|
---|
3735 | </pre></td>
|
---|
3736 | </tr>
|
---|
3737 | </table>
|
---|
3738 | </div>
|
---|
3739 | <p>This program demonstrates the basic concepts involved in
|
---|
3740 | creating a menu using menus library. First we create the items
|
---|
3741 | using new_item() and then attach them to the menu with new_menu()
|
---|
3742 | function. After posting the menu and refreshing the screen, the
|
---|
3743 | main processing loop starts. It reads user input and takes
|
---|
3744 | corresponding action. The function menu_driver() is the main work
|
---|
3745 | horse of the menu system. The second parameter to this function
|
---|
3746 | tells what's to be done with the menu. According to the parameter,
|
---|
3747 | menu_driver() does the corresponding task. The value can be either
|
---|
3748 | a menu navigational request, an ascii character, or a KEY_MOUSE
|
---|
3749 | special key associated with a mouse event.</p>
|
---|
3750 | <p>The menu_driver accepts following navigational requests.</p>
|
---|
3751 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
3752 | <tr>
|
---|
3753 | <td>
|
---|
3754 | <pre class="PROGRAMLISTING">
|
---|
3755 | <font color=
|
---|
3756 | "#000000"> REQ_LEFT_ITEM Move left to an item.
|
---|
3757 | REQ_RIGHT_ITEM Move right to an item.
|
---|
3758 | REQ_UP_ITEM Move up to an item.
|
---|
3759 | REQ_DOWN_ITEM Move down to an item.
|
---|
3760 | REQ_SCR_ULINE Scroll up a line.
|
---|
3761 | REQ_SCR_DLINE Scroll down a line.
|
---|
3762 | REQ_SCR_DPAGE Scroll down a page.
|
---|
3763 | REQ_SCR_UPAGE Scroll up a page.
|
---|
3764 | REQ_FIRST_ITEM Move to the first item.
|
---|
3765 | REQ_LAST_ITEM Move to the last item.
|
---|
3766 | REQ_NEXT_ITEM Move to the next item.
|
---|
3767 | REQ_PREV_ITEM Move to the previous item.
|
---|
3768 | REQ_TOGGLE_ITEM Select/deselect an item.
|
---|
3769 | REQ_CLEAR_PATTERN Clear the menu pattern buffer.
|
---|
3770 | REQ_BACK_PATTERN Delete the previous character from the pattern buffer.
|
---|
3771 | REQ_NEXT_MATCH Move to the next item matching the pattern match.
|
---|
3772 | REQ_PREV_MATCH Move to the previous item matching the pattern match. </font>
|
---|
3773 | </pre></td>
|
---|
3774 | </tr>
|
---|
3775 | </table>
|
---|
3776 | <p>Don't get overwhelmed by the number of options. We will see them
|
---|
3777 | slowly one after another. The options of interest in this example
|
---|
3778 | are REQ_UP_ITEM and REQ_DOWN_ITEM. These two options when passed to
|
---|
3779 | menu_driver, menu driver updates the current item to one item up or
|
---|
3780 | down respectively.</p>
|
---|
3781 | </div>
|
---|
3782 | <div class="SECT2">
|
---|
3783 | <hr>
|
---|
3784 | <h3 class="SECT2"><a name="MENUDRIVER" id="MENUDRIVER">17.3. Menu
|
---|
3785 | Driver: The work horse of the menu system</a></h3>
|
---|
3786 | <p>As you have seen in the above example, menu_driver plays an
|
---|
3787 | important role in updating the menu. It is very important to
|
---|
3788 | understand various options it takes and what they do. As explained
|
---|
3789 | above, the second parameter to menu_driver() can be either a
|
---|
3790 | navigational request, a printable character or a KEY_MOUSE key.
|
---|
3791 | Let's dissect the different navigational requests.</p>
|
---|
3792 | <ul>
|
---|
3793 | <li>
|
---|
3794 | <p><em>REQ_LEFT_ITEM and REQ_RIGHT_ITEM</em></p>
|
---|
3795 | <p>A Menu can be displayed with multiple columns for more than one
|
---|
3796 | item. This can be done by using the <var class=
|
---|
3797 | "LITERAL">menu_format()</var>function. When a multi columnar menu
|
---|
3798 | is displayed these requests cause the menu driver to move the
|
---|
3799 | current selection to left or right.</p>
|
---|
3800 | </li>
|
---|
3801 | <li>
|
---|
3802 | <p><em>REQ_UP_ITEM and REQ_DOWN_ITEM</em></p>
|
---|
3803 | <p>These two options you have seen in the above example. These
|
---|
3804 | options when given, makes the menu_driver to move the current
|
---|
3805 | selection to an item up or down.</p>
|
---|
3806 | </li>
|
---|
3807 | <li>
|
---|
3808 | <p><em>REQ_SCR_* options</em></p>
|
---|
3809 | <p>The four options REQ_SCR_ULINE, REQ_SCR_DLINE, REQ_SCR_DPAGE,
|
---|
3810 | REQ_SCR_UPAGE are related to scrolling. If all the items in the
|
---|
3811 | menu cannot be displayed in the menu sub window, then the menu is
|
---|
3812 | scrollable. These requests can be given to the menu_driver to do
|
---|
3813 | the scrolling either one line up, down or one page down or up
|
---|
3814 | respectively.</p>
|
---|
3815 | </li>
|
---|
3816 | <li>
|
---|
3817 | <p><em>REQ_FIRST_ITEM, REQ_LAST_ITEM, REQ_NEXT_ITEM and
|
---|
3818 | REQ_PREV_ITEM</em></p>
|
---|
3819 | <p>These requests are self explanatory.</p>
|
---|
3820 | </li>
|
---|
3821 | <li>
|
---|
3822 | <p><em>REQ_TOGGLE_ITEM</em></p>
|
---|
3823 | <p>This request when given, toggles the present selection. This
|
---|
3824 | option is to be used only in a multi valued menu. So to use this
|
---|
3825 | request the option O_ONEVALUE must be off. This option can be made
|
---|
3826 | off or on with set_menu_opts().</p>
|
---|
3827 | </li>
|
---|
3828 | <li>
|
---|
3829 | <p><em>Pattern Requests</em></p>
|
---|
3830 | <p>Every menu has an associated pattern buffer, which is used to
|
---|
3831 | find the nearest match to the ascii characters entered by the user.
|
---|
3832 | Whenever ascii characters are given to menu_driver, it puts in to
|
---|
3833 | the pattern buffer. It also tries to find the nearest match to the
|
---|
3834 | pattern in the items list and moves current selection to that item.
|
---|
3835 | The request REQ_CLEAR_PATTERN clears the pattern buffer. The
|
---|
3836 | request REQ_BACK_PATTERN deletes the previous character in the
|
---|
3837 | pattern buffer. In case the pattern matches more than one item then
|
---|
3838 | the matched items can be cycled through REQ_NEXT_MATCH and
|
---|
3839 | REQ_PREV_MATCH which move the current selection to the next and
|
---|
3840 | previous matches respectively.</p>
|
---|
3841 | </li>
|
---|
3842 | <li>
|
---|
3843 | <p><em>Mouse Requests</em></p>
|
---|
3844 | <p>In case of KEY_MOUSE requests, according to the mouse position
|
---|
3845 | an action is taken accordingly. The action to be taken is explained
|
---|
3846 | in the man page as,</p>
|
---|
3847 | <table border="0" bgcolor="#E0E0E0" width="90%">
|
---|
3848 | <tr>
|
---|
3849 | <td>
|
---|
3850 | <pre class="PROGRAMLISTING">
|
---|
3851 | <font color=
|
---|
3852 | "#000000"><em> If the second argument is the KEY_MOUSE special key, the
|
---|
3853 | associated mouse event is translated into one of the above
|
---|
3854 | pre-defined requests. Currently only clicks in the user
|
---|
3855 | window (e.g. inside the menu display area or the decora­
|
---|
3856 | tion window) are handled. If you click above the display
|
---|
3857 | region of the menu, a REQ_SCR_ULINE is generated, if you
|
---|
3858 | doubleclick a REQ_SCR_UPAGE is generated and if you
|
---|
3859 | tripleclick a REQ_FIRST_ITEM is generated. If you click
|
---|
3860 | below the display region of the menu, a REQ_SCR_DLINE is
|
---|
3861 | generated, if you doubleclick a REQ_SCR_DPAGE is generated
|
---|
3862 | and if you tripleclick a REQ_LAST_ITEM is generated. If
|
---|
3863 | you click at an item inside the display area of the menu,
|
---|
3864 | the menu cursor is positioned to that item.</em></font>
|
---|
3865 | </pre></td>
|
---|
3866 | </tr>
|
---|
3867 | </table>
|
---|
3868 | </li>
|
---|
3869 | </ul>
|
---|
3870 | <p>Each of the above requests will be explained in the following
|
---|
3871 | lines with several examples whenever appropriate.</p>
|
---|
3872 | </div>
|
---|
3873 | <div class="SECT2">
|
---|
3874 | <hr>
|
---|
3875 | <h3 class="SECT2"><a name="MENUWINDOWS" id="MENUWINDOWS">17.4. Menu
|
---|
3876 | Windows</a></h3>
|
---|
3877 | <p>Every menu created is associated with a window and a sub window.
|
---|
3878 | The menu window displays any title or border associated with the
|
---|
3879 | menu. The menu sub window displays the menu items currently
|
---|
3880 | available for selection. But we didn't specify any window or sub
|
---|
3881 | window in the simple example. When a window is not specified,
|
---|
3882 | stdscr is taken as the main window, and then menu system calculates
|
---|
3883 | the sub window size required for the display of items. Then items
|
---|
3884 | are displayed in the calculated sub window. So let's play with
|
---|
3885 | these windows and display a menu with a border and a title.</p>
|
---|
3886 | <div class="EXAMPLE"><a name="MMEWI" id="MMEWI"></a>
|
---|
3887 | <p><b>Example 19. Menu Windows Usage example</b></p>
|
---|
3888 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
3889 | <tr>
|
---|
3890 | <td>
|
---|
3891 | <pre class="PROGRAMLISTING">
|
---|
3892 | <font color="#000000"><span class=
|
---|
3893 | "INLINEMEDIAOBJECT">#include <menu.h>
|
---|
3894 |
|
---|
3895 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
---|
3896 | #define CTRLD 4
|
---|
3897 |
|
---|
3898 | char *choices[] = {
|
---|
3899 | "Choice 1",
|
---|
3900 | "Choice 2",
|
---|
3901 | "Choice 3",
|
---|
3902 | "Choice 4",
|
---|
3903 | "Exit",
|
---|
3904 | (char *)NULL,
|
---|
3905 | };
|
---|
3906 | void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color);
|
---|
3907 |
|
---|
3908 | int main()
|
---|
3909 | { ITEM **my_items;
|
---|
3910 | int c;
|
---|
3911 | MENU *my_menu;
|
---|
3912 | WINDOW *my_menu_win;
|
---|
3913 | int n_choices, i;
|
---|
3914 |
|
---|
3915 | /* Initialize curses */
|
---|
3916 | initscr();
|
---|
3917 | start_color();
|
---|
3918 | cbreak();
|
---|
3919 | noecho();
|
---|
3920 | keypad(stdscr, TRUE);
|
---|
3921 | init_pair(1, COLOR_RED, COLOR_BLACK);
|
---|
3922 |
|
---|
3923 | /* Create items */
|
---|
3924 | n_choices = ARRAY_SIZE(choices);
|
---|
3925 | my_items = (ITEM **)calloc(n_choices, sizeof(ITEM *));
|
---|
3926 | for(i = 0; i < n_choices; ++i)
|
---|
3927 | my_items[i] = new_item(choices[i], choices[i]);
|
---|
3928 |
|
---|
3929 | /* Crate menu */
|
---|
3930 | my_menu = new_menu((ITEM **)my_items);
|
---|
3931 |
|
---|
3932 | /* Create the window to be associated with the menu */
|
---|
3933 | my_menu_win = newwin(10, 40, 4, 4);
|
---|
3934 | keypad(my_menu_win, TRUE);
|
---|
3935 |
|
---|
3936 | /* Set main window and sub window */
|
---|
3937 | set_menu_win(my_menu, my_menu_win);
|
---|
3938 | set_menu_sub(my_menu, derwin(my_menu_win, 6, 38, 3, 1));
|
---|
3939 |
|
---|
3940 | /* Set menu mark to the string " * " */
|
---|
3941 | set_menu_mark(my_menu, " * ");
|
---|
3942 |
|
---|
3943 | /* Print a border around the main window and print a title */
|
---|
3944 | box(my_menu_win, 0, 0);
|
---|
3945 | print_in_middle(my_menu_win, 1, 0, 40, "My Menu", COLOR_PAIR(1));
|
---|
3946 | mvwaddch(my_menu_win, 2, 0, ACS_LTEE);
|
---|
3947 | mvwhline(my_menu_win, 2, 1, ACS_HLINE, 38);
|
---|
3948 | mvwaddch(my_menu_win, 2, 39, ACS_RTEE);
|
---|
3949 | mvprintw(LINES - 2, 0, "F1 to exit");
|
---|
3950 | refresh();
|
---|
3951 |
|
---|
3952 | /* Post the menu */
|
---|
3953 | post_menu(my_menu);
|
---|
3954 | wrefresh(my_menu_win);
|
---|
3955 |
|
---|
3956 | while((c = wgetch(my_menu_win)) != KEY_F(1))
|
---|
3957 | { switch(c)
|
---|
3958 | { case KEY_DOWN:
|
---|
3959 | menu_driver(my_menu, REQ_DOWN_ITEM);
|
---|
3960 | break;
|
---|
3961 | case KEY_UP:
|
---|
3962 | menu_driver(my_menu, REQ_UP_ITEM);
|
---|
3963 | break;
|
---|
3964 | }
|
---|
3965 | wrefresh(my_menu_win);
|
---|
3966 | }
|
---|
3967 |
|
---|
3968 | /* Unpost and free all the memory taken up */
|
---|
3969 | unpost_menu(my_menu);
|
---|
3970 | free_menu(my_menu);
|
---|
3971 | for(i = 0; i < n_choices; ++i)
|
---|
3972 | free_item(my_items[i]);
|
---|
3973 | endwin();
|
---|
3974 | }
|
---|
3975 |
|
---|
3976 | void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color)
|
---|
3977 | { int length, x, y;
|
---|
3978 | float temp;
|
---|
3979 |
|
---|
3980 | if(win == NULL)
|
---|
3981 | win = stdscr;
|
---|
3982 | getyx(win, y, x);
|
---|
3983 | if(startx != 0)
|
---|
3984 | x = startx;
|
---|
3985 | if(starty != 0)
|
---|
3986 | y = starty;
|
---|
3987 | if(width == 0)
|
---|
3988 | width = 80;
|
---|
3989 |
|
---|
3990 | length = strlen(string);
|
---|
3991 | temp = (width - length)/ 2;
|
---|
3992 | x = startx + (int)temp;
|
---|
3993 | wattron(win, color);
|
---|
3994 | mvwprintw(win, y, x, "%s", string);
|
---|
3995 | wattroff(win, color);
|
---|
3996 | refresh();
|
---|
3997 | }</span></font>
|
---|
3998 | </pre></td>
|
---|
3999 | </tr>
|
---|
4000 | </table>
|
---|
4001 | </div>
|
---|
4002 | <p>This example creates a menu with a title, border, a fancy line
|
---|
4003 | separating title and the items. As you can see, in order to attach
|
---|
4004 | a window to a menu the function set_menu_win() has to be used. Then
|
---|
4005 | we attach the sub window also. This displays the items in the sub
|
---|
4006 | window. You can also set the mark string which gets displayed to
|
---|
4007 | the left of the selected item with set_menu_mark().</p>
|
---|
4008 | </div>
|
---|
4009 | <div class="SECT2">
|
---|
4010 | <hr>
|
---|
4011 | <h3 class="SECT2"><a name="SCROLLMENUS" id="SCROLLMENUS">17.5.
|
---|
4012 | Scrolling Menus</a></h3>
|
---|
4013 | <p>If the sub window given for a window is not big enough to show
|
---|
4014 | all the items, then the menu will be scrollable. When you are on
|
---|
4015 | the last item in the present list, if you send REQ_DOWN_ITEM, it
|
---|
4016 | gets translated into REQ_SCR_DLINE and the menu scrolls by one
|
---|
4017 | item. You can manually give REQ_SCR_ operations to do scrolling.
|
---|
4018 | Let's see how it can be done.</p>
|
---|
4019 | <div class="EXAMPLE"><a name="MMESC" id="MMESC"></a>
|
---|
4020 | <p><b>Example 20. Scrolling Menus example</b></p>
|
---|
4021 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
4022 | <tr>
|
---|
4023 | <td>
|
---|
4024 | <pre class="PROGRAMLISTING">
|
---|
4025 | <font color="#000000"><span class=
|
---|
4026 | "INLINEMEDIAOBJECT">#include <curses.h>
|
---|
4027 | #include <menu.h>
|
---|
4028 |
|
---|
4029 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
---|
4030 | #define CTRLD 4
|
---|
4031 |
|
---|
4032 | char *choices[] = {
|
---|
4033 | "Choice 1",
|
---|
4034 | "Choice 2",
|
---|
4035 | "Choice 3",
|
---|
4036 | "Choice 4",
|
---|
4037 | "Choice 5",
|
---|
4038 | "Choice 6",
|
---|
4039 | "Choice 7",
|
---|
4040 | "Choice 8",
|
---|
4041 | "Choice 9",
|
---|
4042 | "Choice 10",
|
---|
4043 | "Exit",
|
---|
4044 | (char *)NULL,
|
---|
4045 | };
|
---|
4046 | void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color);
|
---|
4047 |
|
---|
4048 | int main()
|
---|
4049 | { ITEM **my_items;
|
---|
4050 | int c;
|
---|
4051 | MENU *my_menu;
|
---|
4052 | WINDOW *my_menu_win;
|
---|
4053 | int n_choices, i;
|
---|
4054 |
|
---|
4055 | /* Initialize curses */
|
---|
4056 | initscr();
|
---|
4057 | start_color();
|
---|
4058 | cbreak();
|
---|
4059 | noecho();
|
---|
4060 | keypad(stdscr, TRUE);
|
---|
4061 | init_pair(1, COLOR_RED, COLOR_BLACK);
|
---|
4062 | init_pair(2, COLOR_CYAN, COLOR_BLACK);
|
---|
4063 |
|
---|
4064 | /* Create items */
|
---|
4065 | n_choices = ARRAY_SIZE(choices);
|
---|
4066 | my_items = (ITEM **)calloc(n_choices, sizeof(ITEM *));
|
---|
4067 | for(i = 0; i < n_choices; ++i)
|
---|
4068 | my_items[i] = new_item(choices[i], choices[i]);
|
---|
4069 |
|
---|
4070 | /* Crate menu */
|
---|
4071 | my_menu = new_menu((ITEM **)my_items);
|
---|
4072 |
|
---|
4073 | /* Create the window to be associated with the menu */
|
---|
4074 | my_menu_win = newwin(10, 40, 4, 4);
|
---|
4075 | keypad(my_menu_win, TRUE);
|
---|
4076 |
|
---|
4077 | /* Set main window and sub window */
|
---|
4078 | set_menu_win(my_menu, my_menu_win);
|
---|
4079 | set_menu_sub(my_menu, derwin(my_menu_win, 6, 38, 3, 1));
|
---|
4080 | set_menu_format(my_menu, 5, 1);
|
---|
4081 |
|
---|
4082 | /* Set menu mark to the string " * " */
|
---|
4083 | set_menu_mark(my_menu, " * ");
|
---|
4084 |
|
---|
4085 | /* Print a border around the main window and print a title */
|
---|
4086 | box(my_menu_win, 0, 0);
|
---|
4087 | print_in_middle(my_menu_win, 1, 0, 40, "My Menu", COLOR_PAIR(1));
|
---|
4088 | mvwaddch(my_menu_win, 2, 0, ACS_LTEE);
|
---|
4089 | mvwhline(my_menu_win, 2, 1, ACS_HLINE, 38);
|
---|
4090 | mvwaddch(my_menu_win, 2, 39, ACS_RTEE);
|
---|
4091 |
|
---|
4092 | /* Post the menu */
|
---|
4093 | post_menu(my_menu);
|
---|
4094 | wrefresh(my_menu_win);
|
---|
4095 |
|
---|
4096 | attron(COLOR_PAIR(2));
|
---|
4097 | mvprintw(LINES - 2, 0, "Use PageUp and PageDown to scoll down or up a page of items");
|
---|
4098 | mvprintw(LINES - 1, 0, "Arrow Keys to navigate (F1 to Exit)");
|
---|
4099 | attroff(COLOR_PAIR(2));
|
---|
4100 | refresh();
|
---|
4101 |
|
---|
4102 | while((c = wgetch(my_menu_win)) != KEY_F(1))
|
---|
4103 | { switch(c)
|
---|
4104 | { case KEY_DOWN:
|
---|
4105 | menu_driver(my_menu, REQ_DOWN_ITEM);
|
---|
4106 | break;
|
---|
4107 | case KEY_UP:
|
---|
4108 | menu_driver(my_menu, REQ_UP_ITEM);
|
---|
4109 | break;
|
---|
4110 | case KEY_NPAGE:
|
---|
4111 | menu_driver(my_menu, REQ_SCR_DPAGE);
|
---|
4112 | break;
|
---|
4113 | case KEY_PPAGE:
|
---|
4114 | menu_driver(my_menu, REQ_SCR_UPAGE);
|
---|
4115 | break;
|
---|
4116 | }
|
---|
4117 | wrefresh(my_menu_win);
|
---|
4118 | }
|
---|
4119 |
|
---|
4120 | /* Unpost and free all the memory taken up */
|
---|
4121 | unpost_menu(my_menu);
|
---|
4122 | free_menu(my_menu);
|
---|
4123 | for(i = 0; i < n_choices; ++i)
|
---|
4124 | free_item(my_items[i]);
|
---|
4125 | endwin();
|
---|
4126 | }
|
---|
4127 |
|
---|
4128 | void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color)
|
---|
4129 | { int length, x, y;
|
---|
4130 | float temp;
|
---|
4131 |
|
---|
4132 | if(win == NULL)
|
---|
4133 | win = stdscr;
|
---|
4134 | getyx(win, y, x);
|
---|
4135 | if(startx != 0)
|
---|
4136 | x = startx;
|
---|
4137 | if(starty != 0)
|
---|
4138 | y = starty;
|
---|
4139 | if(width == 0)
|
---|
4140 | width = 80;
|
---|
4141 |
|
---|
4142 | length = strlen(string);
|
---|
4143 | temp = (width - length)/ 2;
|
---|
4144 | x = startx + (int)temp;
|
---|
4145 | wattron(win, color);
|
---|
4146 | mvwprintw(win, y, x, "%s", string);
|
---|
4147 | wattroff(win, color);
|
---|
4148 | refresh();
|
---|
4149 | }</span></font>
|
---|
4150 | </pre></td>
|
---|
4151 | </tr>
|
---|
4152 | </table>
|
---|
4153 | </div>
|
---|
4154 | <p>This program is self-explanatory. In this example the number of
|
---|
4155 | choices has been increased to ten, which is larger than our sub
|
---|
4156 | window size which can hold 6 items. This message has to be
|
---|
4157 | explicitly conveyed to the menu system with the function
|
---|
4158 | set_menu_format(). In here we specify the number of rows and
|
---|
4159 | columns we want to be displayed for a single page. We can specify
|
---|
4160 | any number of items to be shown, in the rows variables, if it is
|
---|
4161 | less than the height of the sub window. If the key pressed by the
|
---|
4162 | user is a PAGE UP or PAGE DOWN, the menu is scrolled a page due to
|
---|
4163 | the requests (REQ_SCR_DPAGE and REQ_SCR_UPAGE) given to
|
---|
4164 | menu_driver().</p>
|
---|
4165 | </div>
|
---|
4166 | <div class="SECT2">
|
---|
4167 | <hr>
|
---|
4168 | <h3 class="SECT2"><a name="MULTICOLUMN" id="MULTICOLUMN">17.6.
|
---|
4169 | Multi Columnar Menus</a></h3>
|
---|
4170 | <p>In the above example you have seen how to use the function
|
---|
4171 | set_menu_format(). I didn't mention what the cols variable (third
|
---|
4172 | parameter) does. Well, If your sub window is wide enough, you can
|
---|
4173 | opt to display more than one item per row. This can be specified in
|
---|
4174 | the cols variable. To make things simpler, the following example
|
---|
4175 | doesn't show descriptions for the items.</p>
|
---|
4176 | <div class="EXAMPLE"><a name="MMEMUCO" id="MMEMUCO"></a>
|
---|
4177 | <p><b>Example 21. Milt Columnar Menus Example</b></p>
|
---|
4178 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
4179 | <tr>
|
---|
4180 | <td>
|
---|
4181 | <pre class="PROGRAMLISTING">
|
---|
4182 | <font color="#000000"><span class=
|
---|
4183 | "INLINEMEDIAOBJECT">#include <curses.h>
|
---|
4184 | #include <menu.h>
|
---|
4185 |
|
---|
4186 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
---|
4187 | #define CTRLD 4
|
---|
4188 |
|
---|
4189 | char *choices[] = {
|
---|
4190 | "Choice 1", "Choice 2", "Choice 3", "Choice 4", "Choice 5",
|
---|
4191 | "Choice 6", "Choice 7", "Choice 8", "Choice 9", "Choice 10",
|
---|
4192 | "Choice 11", "Choice 12", "Choice 13", "Choice 14", "Choice 15",
|
---|
4193 | "Choice 16", "Choice 17", "Choice 18", "Choice 19", "Choice 20",
|
---|
4194 | "Exit",
|
---|
4195 | (char *)NULL,
|
---|
4196 | };
|
---|
4197 |
|
---|
4198 | int main()
|
---|
4199 | { ITEM **my_items;
|
---|
4200 | int c;
|
---|
4201 | MENU *my_menu;
|
---|
4202 | WINDOW *my_menu_win;
|
---|
4203 | int n_choices, i;
|
---|
4204 |
|
---|
4205 | /* Initialize curses */
|
---|
4206 | initscr();
|
---|
4207 | start_color();
|
---|
4208 | cbreak();
|
---|
4209 | noecho();
|
---|
4210 | keypad(stdscr, TRUE);
|
---|
4211 | init_pair(1, COLOR_RED, COLOR_BLACK);
|
---|
4212 | init_pair(2, COLOR_CYAN, COLOR_BLACK);
|
---|
4213 |
|
---|
4214 | /* Create items */
|
---|
4215 | n_choices = ARRAY_SIZE(choices);
|
---|
4216 | my_items = (ITEM **)calloc(n_choices, sizeof(ITEM *));
|
---|
4217 | for(i = 0; i < n_choices; ++i)
|
---|
4218 | my_items[i] = new_item(choices[i], choices[i]);
|
---|
4219 |
|
---|
4220 | /* Crate menu */
|
---|
4221 | my_menu = new_menu((ITEM **)my_items);
|
---|
4222 |
|
---|
4223 | /* Set menu option not to show the description */
|
---|
4224 | menu_opts_off(my_menu, O_SHOWDESC);
|
---|
4225 |
|
---|
4226 | /* Create the window to be associated with the menu */
|
---|
4227 | my_menu_win = newwin(10, 70, 4, 4);
|
---|
4228 | keypad(my_menu_win, TRUE);
|
---|
4229 |
|
---|
4230 | /* Set main window and sub window */
|
---|
4231 | set_menu_win(my_menu, my_menu_win);
|
---|
4232 | set_menu_sub(my_menu, derwin(my_menu_win, 6, 68, 3, 1));
|
---|
4233 | set_menu_format(my_menu, 5, 3);
|
---|
4234 | set_menu_mark(my_menu, " * ");
|
---|
4235 |
|
---|
4236 | /* Print a border around the main window and print a title */
|
---|
4237 | box(my_menu_win, 0, 0);
|
---|
4238 |
|
---|
4239 | attron(COLOR_PAIR(2));
|
---|
4240 | mvprintw(LINES - 3, 0, "Use PageUp and PageDown to scroll");
|
---|
4241 | mvprintw(LINES - 2, 0, "Use Arrow Keys to navigate (F1 to Exit)");
|
---|
4242 | attroff(COLOR_PAIR(2));
|
---|
4243 | refresh();
|
---|
4244 |
|
---|
4245 | /* Post the menu */
|
---|
4246 | post_menu(my_menu);
|
---|
4247 | wrefresh(my_menu_win);
|
---|
4248 |
|
---|
4249 | while((c = wgetch(my_menu_win)) != KEY_F(1))
|
---|
4250 | { switch(c)
|
---|
4251 | { case KEY_DOWN:
|
---|
4252 | menu_driver(my_menu, REQ_DOWN_ITEM);
|
---|
4253 | break;
|
---|
4254 | case KEY_UP:
|
---|
4255 | menu_driver(my_menu, REQ_UP_ITEM);
|
---|
4256 | break;
|
---|
4257 | case KEY_LEFT:
|
---|
4258 | menu_driver(my_menu, REQ_LEFT_ITEM);
|
---|
4259 | break;
|
---|
4260 | case KEY_RIGHT:
|
---|
4261 | menu_driver(my_menu, REQ_RIGHT_ITEM);
|
---|
4262 | break;
|
---|
4263 | case KEY_NPAGE:
|
---|
4264 | menu_driver(my_menu, REQ_SCR_DPAGE);
|
---|
4265 | break;
|
---|
4266 | case KEY_PPAGE:
|
---|
4267 | menu_driver(my_menu, REQ_SCR_UPAGE);
|
---|
4268 | break;
|
---|
4269 | }
|
---|
4270 | wrefresh(my_menu_win);
|
---|
4271 | }
|
---|
4272 |
|
---|
4273 | /* Unpost and free all the memory taken up */
|
---|
4274 | unpost_menu(my_menu);
|
---|
4275 | free_menu(my_menu);
|
---|
4276 | for(i = 0; i < n_choices; ++i)
|
---|
4277 | free_item(my_items[i]);
|
---|
4278 | endwin();
|
---|
4279 | }</span></font>
|
---|
4280 | </pre></td>
|
---|
4281 | </tr>
|
---|
4282 | </table>
|
---|
4283 | </div>
|
---|
4284 | <p>Watch the function call to set_menu_format(). It specifies the
|
---|
4285 | number of columns to be 3, thus displaying 3 items per row. We have
|
---|
4286 | also switched off the showing descriptions with the function
|
---|
4287 | menu_opts_off(). There are couple of functions set_menu_opts(),
|
---|
4288 | menu_opts_on() and menu_opts() which can be used to manipulate menu
|
---|
4289 | options. The following menu options can be specified.</p>
|
---|
4290 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
4291 | <tr>
|
---|
4292 | <td>
|
---|
4293 | <pre class="PROGRAMLISTING">
|
---|
4294 | <font color="#000000"> O_ONEVALUE
|
---|
4295 | Only one item can be selected for this menu.
|
---|
4296 |
|
---|
4297 | O_SHOWDESC
|
---|
4298 | Display the item descriptions when the menu is
|
---|
4299 | posted.
|
---|
4300 |
|
---|
4301 | O_ROWMAJOR
|
---|
4302 | Display the menu in row-major order.
|
---|
4303 |
|
---|
4304 | O_IGNORECASE
|
---|
4305 | Ignore the case when pattern-matching.
|
---|
4306 |
|
---|
4307 | O_SHOWMATCH
|
---|
4308 | Move the cursor to within the item name while pat­
|
---|
4309 | tern-matching.
|
---|
4310 |
|
---|
4311 | O_NONCYCLIC
|
---|
4312 | Don't wrap around next-item and previous-item,
|
---|
4313 | requests to the other end of the menu.</font>
|
---|
4314 | </pre></td>
|
---|
4315 | </tr>
|
---|
4316 | </table>
|
---|
4317 | <p>All options are on by default. You can switch specific
|
---|
4318 | attributes on or off with menu_opts_on() and menu_opts_off()
|
---|
4319 | functions. You can also use set_menu_opts() to directly specify the
|
---|
4320 | options. The argument to this function should be a OR ed value of
|
---|
4321 | some of those above constants. The function menu_opts() can be used
|
---|
4322 | to find out a menu's present options.</p>
|
---|
4323 | </div>
|
---|
4324 | <div class="SECT2">
|
---|
4325 | <hr>
|
---|
4326 | <h3 class="SECT2"><a name="MULTIVALUEMENUS" id=
|
---|
4327 | "MULTIVALUEMENUS">17.7. Multi Valued Menus</a></h3>
|
---|
4328 | <p>You might be wondering what if you switch off the option
|
---|
4329 | O_ONEVALUE. Then the menu becomes multi-valued. That means you can
|
---|
4330 | select more than one item. This brings us to the request
|
---|
4331 | REQ_TOGGLE_ITEM. Let's see it in action.</p>
|
---|
4332 | <div class="EXAMPLE"><a name="MMETO" id="MMETO"></a>
|
---|
4333 | <p><b>Example 22. Multi Valued Menus example</b></p>
|
---|
4334 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
4335 | <tr>
|
---|
4336 | <td>
|
---|
4337 | <pre class="PROGRAMLISTING">
|
---|
4338 | <font color="#000000"><span class=
|
---|
4339 | "INLINEMEDIAOBJECT">#include <curses.h>
|
---|
4340 | #include <menu.h>
|
---|
4341 |
|
---|
4342 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
---|
4343 | #define CTRLD 4
|
---|
4344 |
|
---|
4345 | char *choices[] = {
|
---|
4346 | "Choice 1",
|
---|
4347 | "Choice 2",
|
---|
4348 | "Choice 3",
|
---|
4349 | "Choice 4",
|
---|
4350 | "Choice 5",
|
---|
4351 | "Choice 6",
|
---|
4352 | "Choice 7",
|
---|
4353 | "Exit",
|
---|
4354 | };
|
---|
4355 |
|
---|
4356 | int main()
|
---|
4357 | { ITEM **my_items;
|
---|
4358 | int c;
|
---|
4359 | MENU *my_menu;
|
---|
4360 | int n_choices, i;
|
---|
4361 | ITEM *cur_item;
|
---|
4362 |
|
---|
4363 | /* Initialize curses */
|
---|
4364 | initscr();
|
---|
4365 | cbreak();
|
---|
4366 | noecho();
|
---|
4367 | keypad(stdscr, TRUE);
|
---|
4368 |
|
---|
4369 | /* Initialize items */
|
---|
4370 | n_choices = ARRAY_SIZE(choices);
|
---|
4371 | my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *));
|
---|
4372 | for(i = 0; i < n_choices; ++i)
|
---|
4373 | my_items[i] = new_item(choices[i], choices[i]);
|
---|
4374 | my_items[n_choices] = (ITEM *)NULL;
|
---|
4375 |
|
---|
4376 | my_menu = new_menu((ITEM **)my_items);
|
---|
4377 |
|
---|
4378 | /* Make the menu multi valued */
|
---|
4379 | menu_opts_off(my_menu, O_ONEVALUE);
|
---|
4380 |
|
---|
4381 | mvprintw(LINES - 3, 0, "Use <SPACE> to select or unselect an item.");
|
---|
4382 | mvprintw(LINES - 2, 0, "<ENTER> to see presently selected items(F1 to Exit)");
|
---|
4383 | post_menu(my_menu);
|
---|
4384 | refresh();
|
---|
4385 |
|
---|
4386 | while((c = getch()) != KEY_F(1))
|
---|
4387 | { switch(c)
|
---|
4388 | { case KEY_DOWN:
|
---|
4389 | menu_driver(my_menu, REQ_DOWN_ITEM);
|
---|
4390 | break;
|
---|
4391 | case KEY_UP:
|
---|
4392 | menu_driver(my_menu, REQ_UP_ITEM);
|
---|
4393 | break;
|
---|
4394 | case ' ':
|
---|
4395 | menu_driver(my_menu, REQ_TOGGLE_ITEM);
|
---|
4396 | break;
|
---|
4397 | case 10: /* Enter */
|
---|
4398 | { char temp[200];
|
---|
4399 | ITEM **items;
|
---|
4400 |
|
---|
4401 | items = menu_items(my_menu);
|
---|
4402 | temp[0] = '\0';
|
---|
4403 | for(i = 0; i < item_count(my_menu); ++i)
|
---|
4404 | if(item_value(items[i]) == TRUE)
|
---|
4405 | { strcat(temp, item_name(items[i]));
|
---|
4406 | strcat(temp, " ");
|
---|
4407 | }
|
---|
4408 | move(20, 0);
|
---|
4409 | clrtoeol();
|
---|
4410 | mvprintw(20, 0, temp);
|
---|
4411 | refresh();
|
---|
4412 | }
|
---|
4413 | break;
|
---|
4414 | }
|
---|
4415 | }
|
---|
4416 |
|
---|
4417 | free_item(my_items[0]);
|
---|
4418 | free_item(my_items[1]);
|
---|
4419 | free_menu(my_menu);
|
---|
4420 | endwin();
|
---|
4421 | }
|
---|
4422 | </span></font>
|
---|
4423 | </pre></td>
|
---|
4424 | </tr>
|
---|
4425 | </table>
|
---|
4426 | </div>
|
---|
4427 | <p>Whew, A lot of new functions. Let's take them one after another.
|
---|
4428 | Firstly, the REQ_TOGGLE_ITEM. In a multi-valued menu, the user
|
---|
4429 | should be allowed to select or un select more than one item. The
|
---|
4430 | request REQ_TOGGLE_ITEM toggles the present selection. In this case
|
---|
4431 | when space is pressed REQ_TOGGLE_ITEM request is sent to
|
---|
4432 | menu_driver to achieve the result.</p>
|
---|
4433 | <p>Now when the user presses <ENTER> we show the items he
|
---|
4434 | presently selected. First we find out the items associated with the
|
---|
4435 | menu using the function menu_items(). Then we loop through the
|
---|
4436 | items to find out if the item is selected or not. The function
|
---|
4437 | item_value() returns TRUE if an item is selected. The function
|
---|
4438 | item_count() returns the number of items in the menu. The item name
|
---|
4439 | can be found with item_name(). You can also find the description
|
---|
4440 | associated with an item using item_description().</p>
|
---|
4441 | </div>
|
---|
4442 | <div class="SECT2">
|
---|
4443 | <hr>
|
---|
4444 | <h3 class="SECT2"><a name="MENUOPT" id="MENUOPT">17.8. Menu
|
---|
4445 | Options</a></h3>
|
---|
4446 | <p>Well, by this time you must be itching for some difference in
|
---|
4447 | your menu, with lots of functionality. I know. You want Colors !!!.
|
---|
4448 | You want to create nice menus similar to those text mode <a href=
|
---|
4449 | "http://www.jersey.net/~debinjoe/games/" target="_top">dos
|
---|
4450 | games</a>. The functions set_menu_fore() and set_menu_back() can be
|
---|
4451 | used to change the attribute of the selected item and unselected
|
---|
4452 | item. The names are misleading. They don't change menu's foreground
|
---|
4453 | or background which would have been useless.</p>
|
---|
4454 | <p>The function set_menu_grey() can be used to set the display
|
---|
4455 | attribute for the non-selectable items in the menu. This brings us
|
---|
4456 | to the interesting option for an item the one and only
|
---|
4457 | O_SELECTABLE. We can turn it off by the function item_opts_off()
|
---|
4458 | and after that that item is not selectable. It's like a grayed item
|
---|
4459 | in those fancy windows menus. Let's put these concepts in practice
|
---|
4460 | with this example</p>
|
---|
4461 | <div class="EXAMPLE"><a name="MMEAT" id="MMEAT"></a>
|
---|
4462 | <p><b>Example 23. Menu Options example</b></p>
|
---|
4463 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
4464 | <tr>
|
---|
4465 | <td>
|
---|
4466 | <pre class="PROGRAMLISTING">
|
---|
4467 | <font color="#000000"><span class=
|
---|
4468 | "INLINEMEDIAOBJECT">#include <menu.h>
|
---|
4469 |
|
---|
4470 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
---|
4471 | #define CTRLD 4
|
---|
4472 |
|
---|
4473 | char *choices[] = {
|
---|
4474 | "Choice 1",
|
---|
4475 | "Choice 2",
|
---|
4476 | "Choice 3",
|
---|
4477 | "Choice 4",
|
---|
4478 | "Choice 5",
|
---|
4479 | "Choice 6",
|
---|
4480 | "Choice 7",
|
---|
4481 | "Exit",
|
---|
4482 | };
|
---|
4483 |
|
---|
4484 | int main()
|
---|
4485 | { ITEM **my_items;
|
---|
4486 | int c;
|
---|
4487 | MENU *my_menu;
|
---|
4488 | int n_choices, i;
|
---|
4489 | ITEM *cur_item;
|
---|
4490 |
|
---|
4491 | /* Initialize curses */
|
---|
4492 | initscr();
|
---|
4493 | start_color();
|
---|
4494 | cbreak();
|
---|
4495 | noecho();
|
---|
4496 | keypad(stdscr, TRUE);
|
---|
4497 | init_pair(1, COLOR_RED, COLOR_BLACK);
|
---|
4498 | init_pair(2, COLOR_GREEN, COLOR_BLACK);
|
---|
4499 | init_pair(3, COLOR_MAGENTA, COLOR_BLACK);
|
---|
4500 |
|
---|
4501 | /* Initialize items */
|
---|
4502 | n_choices = ARRAY_SIZE(choices);
|
---|
4503 | my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *));
|
---|
4504 | for(i = 0; i < n_choices; ++i)
|
---|
4505 | my_items[i] = new_item(choices[i], choices[i]);
|
---|
4506 | my_items[n_choices] = (ITEM *)NULL;
|
---|
4507 | item_opts_off(my_items[3], O_SELECTABLE);
|
---|
4508 | item_opts_off(my_items[6], O_SELECTABLE);
|
---|
4509 |
|
---|
4510 | /* Create menu */
|
---|
4511 | my_menu = new_menu((ITEM **)my_items);
|
---|
4512 |
|
---|
4513 | /* Set fore ground and back ground of the menu */
|
---|
4514 | set_menu_fore(my_menu, COLOR_PAIR(1) | A_REVERSE);
|
---|
4515 | set_menu_back(my_menu, COLOR_PAIR(2));
|
---|
4516 | set_menu_grey(my_menu, COLOR_PAIR(3));
|
---|
4517 |
|
---|
4518 | /* Post the menu */
|
---|
4519 | mvprintw(LINES - 3, 0, "Press <ENTER> to see the option selected");
|
---|
4520 | mvprintw(LINES - 2, 0, "Up and Down arrow keys to naviage (F1 to Exit)");
|
---|
4521 | post_menu(my_menu);
|
---|
4522 | refresh();
|
---|
4523 |
|
---|
4524 | while((c = getch()) != KEY_F(1))
|
---|
4525 | { switch(c)
|
---|
4526 | { case KEY_DOWN:
|
---|
4527 | menu_driver(my_menu, REQ_DOWN_ITEM);
|
---|
4528 | break;
|
---|
4529 | case KEY_UP:
|
---|
4530 | menu_driver(my_menu, REQ_UP_ITEM);
|
---|
4531 | break;
|
---|
4532 | case 10: /* Enter */
|
---|
4533 | move(20, 0);
|
---|
4534 | clrtoeol();
|
---|
4535 | mvprintw(20, 0, "Item selected is : %s",
|
---|
4536 | item_name(current_item(my_menu)));
|
---|
4537 | pos_menu_cursor(my_menu);
|
---|
4538 | break;
|
---|
4539 | }
|
---|
4540 | }
|
---|
4541 | unpost_menu(my_menu);
|
---|
4542 | for(i = 0; i < n_choices; ++i)
|
---|
4543 | free_item(my_items[i]);
|
---|
4544 | free_menu(my_menu);
|
---|
4545 | endwin();
|
---|
4546 | }
|
---|
4547 | </span></font>
|
---|
4548 | </pre></td>
|
---|
4549 | </tr>
|
---|
4550 | </table>
|
---|
4551 | </div>
|
---|
4552 | </div>
|
---|
4553 | <div class="SECT2">
|
---|
4554 | <hr>
|
---|
4555 | <h3 class="SECT2"><a name="MENUUSERPTR" id="MENUUSERPTR">17.9. The
|
---|
4556 | useful User Pointer</a></h3>
|
---|
4557 | <p>We can associate a user pointer with each item in the menu. It
|
---|
4558 | works the same way as user pointer in panels. It's not touched by
|
---|
4559 | menu system. You can store any thing you like in that. I usually
|
---|
4560 | use it to store the function to be executed when the menu option is
|
---|
4561 | chosen (It's selected and may be the user pressed
|
---|
4562 | <ENTER>);</p>
|
---|
4563 | <div class="EXAMPLE"><a name="MMEUS" id="MMEUS"></a>
|
---|
4564 | <p><b>Example 24. Menu User Pointer Usage</b></p>
|
---|
4565 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
4566 | <tr>
|
---|
4567 | <td>
|
---|
4568 | <pre class="PROGRAMLISTING">
|
---|
4569 | <font color="#000000"><span class=
|
---|
4570 | "INLINEMEDIAOBJECT">#include <curses.h>
|
---|
4571 | #include <menu.h>
|
---|
4572 |
|
---|
4573 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
---|
4574 | #define CTRLD 4
|
---|
4575 |
|
---|
4576 | char *choices[] = {
|
---|
4577 | "Choice 1",
|
---|
4578 | "Choice 2",
|
---|
4579 | "Choice 3",
|
---|
4580 | "Choice 4",
|
---|
4581 | "Choice 5",
|
---|
4582 | "Choice 6",
|
---|
4583 | "Choice 7",
|
---|
4584 | "Exit",
|
---|
4585 | };
|
---|
4586 | void func(char *name);
|
---|
4587 |
|
---|
4588 | int main()
|
---|
4589 | { ITEM **my_items;
|
---|
4590 | int c;
|
---|
4591 | MENU *my_menu;
|
---|
4592 | int n_choices, i;
|
---|
4593 | ITEM *cur_item;
|
---|
4594 |
|
---|
4595 | /* Initialize curses */
|
---|
4596 | initscr();
|
---|
4597 | start_color();
|
---|
4598 | cbreak();
|
---|
4599 | noecho();
|
---|
4600 | keypad(stdscr, TRUE);
|
---|
4601 | init_pair(1, COLOR_RED, COLOR_BLACK);
|
---|
4602 | init_pair(2, COLOR_GREEN, COLOR_BLACK);
|
---|
4603 | init_pair(3, COLOR_MAGENTA, COLOR_BLACK);
|
---|
4604 |
|
---|
4605 | /* Initialize items */
|
---|
4606 | n_choices = ARRAY_SIZE(choices);
|
---|
4607 | my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *));
|
---|
4608 | for(i = 0; i < n_choices; ++i)
|
---|
4609 | { my_items[i] = new_item(choices[i], choices[i]);
|
---|
4610 | /* Set the user pointer */
|
---|
4611 | set_item_userptr(my_items[i], func);
|
---|
4612 | }
|
---|
4613 | my_items[n_choices] = (ITEM *)NULL;
|
---|
4614 |
|
---|
4615 | /* Create menu */
|
---|
4616 | my_menu = new_menu((ITEM **)my_items);
|
---|
4617 |
|
---|
4618 | /* Post the menu */
|
---|
4619 | mvprintw(LINES - 3, 0, "Press <ENTER> to see the option selected");
|
---|
4620 | mvprintw(LINES - 2, 0, "Up and Down arrow keys to naviage (F1 to Exit)");
|
---|
4621 | post_menu(my_menu);
|
---|
4622 | refresh();
|
---|
4623 |
|
---|
4624 | while((c = getch()) != KEY_F(1))
|
---|
4625 | { switch(c)
|
---|
4626 | { case KEY_DOWN:
|
---|
4627 | menu_driver(my_menu, REQ_DOWN_ITEM);
|
---|
4628 | break;
|
---|
4629 | case KEY_UP:
|
---|
4630 | menu_driver(my_menu, REQ_UP_ITEM);
|
---|
4631 | break;
|
---|
4632 | case 10: /* Enter */
|
---|
4633 | { ITEM *cur;
|
---|
4634 | void (*p)(char *);
|
---|
4635 |
|
---|
4636 | cur = current_item(my_menu);
|
---|
4637 | p = item_userptr(cur);
|
---|
4638 | p((char *)item_name(cur));
|
---|
4639 | pos_menu_cursor(my_menu);
|
---|
4640 | break;
|
---|
4641 | }
|
---|
4642 | break;
|
---|
4643 | }
|
---|
4644 | }
|
---|
4645 | unpost_menu(my_menu);
|
---|
4646 | for(i = 0; i < n_choices; ++i)
|
---|
4647 | free_item(my_items[i]);
|
---|
4648 | free_menu(my_menu);
|
---|
4649 | endwin();
|
---|
4650 | }
|
---|
4651 |
|
---|
4652 | void func(char *name)
|
---|
4653 | { move(20, 0);
|
---|
4654 | clrtoeol();
|
---|
4655 | mvprintw(20, 0, "Item selected is : %s", name);
|
---|
4656 | } </span></font>
|
---|
4657 | </pre></td>
|
---|
4658 | </tr>
|
---|
4659 | </table>
|
---|
4660 | </div>
|
---|
4661 | </div>
|
---|
4662 | </div>
|
---|
4663 | <div class="SECT1">
|
---|
4664 | <hr>
|
---|
4665 | <h2 class="SECT1"><a name="FORMS" id="FORMS">18. Forms
|
---|
4666 | Library</a></h2>
|
---|
4667 | <p>Well. If you have seen those forms on web pages which take input
|
---|
4668 | from users and do various kinds of things, you might be wondering
|
---|
4669 | how would any one create such forms in text mode display. It's
|
---|
4670 | quite difficult to write those nifty forms in plain ncurses. Forms
|
---|
4671 | library tries to provide a basic frame work to build and maintain
|
---|
4672 | forms with ease. It has lot of features(functions) which manage
|
---|
4673 | validation, dynamic expansion of fields etc.. Let's see it in full
|
---|
4674 | flow.</p>
|
---|
4675 | <p>A form is a collection of fields; each field can be either a
|
---|
4676 | label(static text) or a data-entry location. The forms also library
|
---|
4677 | provides functions to divide forms into multiple pages.</p>
|
---|
4678 | <div class="SECT2">
|
---|
4679 | <hr>
|
---|
4680 | <h3 class="SECT2"><a name="FORMBASICS" id="FORMBASICS">18.1. The
|
---|
4681 | Basics</a></h3>
|
---|
4682 | <p>Forms are created in much the same way as menus. First the
|
---|
4683 | fields related to the form are created with new_field(). You can
|
---|
4684 | set options for the fields, so that they can be displayed with some
|
---|
4685 | fancy attributes, validated before the field looses focus etc..
|
---|
4686 | Then the fields are attached to form. After this, the form can be
|
---|
4687 | posted to display and is ready to receive inputs. On the similar
|
---|
4688 | lines to menu_driver(), the form is manipulated with form_driver().
|
---|
4689 | We can send requests to form_driver to move focus to a certain
|
---|
4690 | field, move cursor to end of the field etc.. After the user enters
|
---|
4691 | values in the fields and validation done, form can be unposted and
|
---|
4692 | memory allocated can be freed.</p>
|
---|
4693 | <p>The general flow of control of a forms program looks like
|
---|
4694 | this.</p>
|
---|
4695 | <ol type="1">
|
---|
4696 | <li>
|
---|
4697 | <p>Initialize curses</p>
|
---|
4698 | </li>
|
---|
4699 | <li>
|
---|
4700 | <p>Create fields using new_field(). You can specify the height and
|
---|
4701 | width of the field, and its position on the form.</p>
|
---|
4702 | </li>
|
---|
4703 | <li>
|
---|
4704 | <p>Create the forms with new_form() by specifying the fields to be
|
---|
4705 | attached with.</p>
|
---|
4706 | </li>
|
---|
4707 | <li>
|
---|
4708 | <p>Post the form with form_post() and refresh the screen.</p>
|
---|
4709 | </li>
|
---|
4710 | <li>
|
---|
4711 | <p>Process the user requests with a loop and do necessary updates
|
---|
4712 | to form with form_driver.</p>
|
---|
4713 | </li>
|
---|
4714 | <li>
|
---|
4715 | <p>Unpost the menu with form_unpost()</p>
|
---|
4716 | </li>
|
---|
4717 | <li>
|
---|
4718 | <p>Free the memory allocated to menu by free_form()</p>
|
---|
4719 | </li>
|
---|
4720 | <li>
|
---|
4721 | <p>Free the memory allocated to the items with free_field()</p>
|
---|
4722 | </li>
|
---|
4723 | <li>
|
---|
4724 | <p>End curses</p>
|
---|
4725 | </li>
|
---|
4726 | </ol>
|
---|
4727 | <p>As you can see, working with forms library is much similar to
|
---|
4728 | handling menu library. The following examples will explore various
|
---|
4729 | aspects of form processing. Let's start the journey with a simple
|
---|
4730 | example. first.</p>
|
---|
4731 | </div>
|
---|
4732 | <div class="SECT2">
|
---|
4733 | <hr>
|
---|
4734 | <h3 class="SECT2"><a name="COMPILEFORMS" id="COMPILEFORMS">18.2.
|
---|
4735 | Compiling With the Forms Library</a></h3>
|
---|
4736 | <p>To use forms library functions, you have to include form.h and
|
---|
4737 | to link the program with forms library the flag -lform should be
|
---|
4738 | added along with -lncurses in that order.</p>
|
---|
4739 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
4740 | <tr>
|
---|
4741 | <td>
|
---|
4742 | <pre class="PROGRAMLISTING">
|
---|
4743 | <font color="#000000"> #include <form.h>
|
---|
4744 | .
|
---|
4745 | .
|
---|
4746 | .
|
---|
4747 |
|
---|
4748 | compile and link: gcc <program file> -lform -lncurses</font>
|
---|
4749 | </pre></td>
|
---|
4750 | </tr>
|
---|
4751 | </table>
|
---|
4752 | <div class="EXAMPLE"><a name="FFOSI" id="FFOSI"></a>
|
---|
4753 | <p><b>Example 25. Forms Basics</b></p>
|
---|
4754 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
4755 | <tr>
|
---|
4756 | <td>
|
---|
4757 | <pre class="PROGRAMLISTING">
|
---|
4758 | <font color="#000000"><span class=
|
---|
4759 | "INLINEMEDIAOBJECT">#include <form.h>
|
---|
4760 |
|
---|
4761 | int main()
|
---|
4762 | { FIELD *field[3];
|
---|
4763 | FORM *my_form;
|
---|
4764 | int ch;
|
---|
4765 |
|
---|
4766 | /* Initialize curses */
|
---|
4767 | initscr();
|
---|
4768 | cbreak();
|
---|
4769 | noecho();
|
---|
4770 | keypad(stdscr, TRUE);
|
---|
4771 |
|
---|
4772 | /* Initialize the fields */
|
---|
4773 | field[0] = new_field(1, 10, 4, 18, 0, 0);
|
---|
4774 | field[1] = new_field(1, 10, 6, 18, 0, 0);
|
---|
4775 | field[2] = NULL;
|
---|
4776 |
|
---|
4777 | /* Set field options */
|
---|
4778 | set_field_back(field[0], A_UNDERLINE); /* Print a line for the option */
|
---|
4779 | field_opts_off(field[0], O_AUTOSKIP); /* Don't go to next field when this */
|
---|
4780 | /* Field is filled up */
|
---|
4781 | set_field_back(field[1], A_UNDERLINE);
|
---|
4782 | field_opts_off(field[1], O_AUTOSKIP);
|
---|
4783 |
|
---|
4784 | /* Create the form and post it */
|
---|
4785 | my_form = new_form(field);
|
---|
4786 | post_form(my_form);
|
---|
4787 | refresh();
|
---|
4788 |
|
---|
4789 | mvprintw(4, 10, "Value 1:");
|
---|
4790 | mvprintw(6, 10, "Value 2:");
|
---|
4791 | refresh();
|
---|
4792 |
|
---|
4793 | /* Loop through to get user requests */
|
---|
4794 | while((ch = getch()) != KEY_F(1))
|
---|
4795 | { switch(ch)
|
---|
4796 | { case KEY_DOWN:
|
---|
4797 | /* Go to next field */
|
---|
4798 | form_driver(my_form, REQ_NEXT_FIELD);
|
---|
4799 | /* Go to the end of the present buffer */
|
---|
4800 | /* Leaves nicely at the last character */
|
---|
4801 | form_driver(my_form, REQ_END_LINE);
|
---|
4802 | break;
|
---|
4803 | case KEY_UP:
|
---|
4804 | /* Go to previous field */
|
---|
4805 | form_driver(my_form, REQ_PREV_FIELD);
|
---|
4806 | form_driver(my_form, REQ_END_LINE);
|
---|
4807 | break;
|
---|
4808 | default:
|
---|
4809 | /* If this is a normal character, it gets */
|
---|
4810 | /* Printed */
|
---|
4811 | form_driver(my_form, ch);
|
---|
4812 | break;
|
---|
4813 | }
|
---|
4814 | }
|
---|
4815 |
|
---|
4816 | /* Un post form and free the memory */
|
---|
4817 | unpost_form(my_form);
|
---|
4818 | free_form(my_form);
|
---|
4819 | free_field(field[0]);
|
---|
4820 | free_field(field[1]);
|
---|
4821 |
|
---|
4822 | endwin();
|
---|
4823 | return 0;
|
---|
4824 | }</span></font>
|
---|
4825 | </pre></td>
|
---|
4826 | </tr>
|
---|
4827 | </table>
|
---|
4828 | </div>
|
---|
4829 | <p>Above example is pretty straight forward. It creates two fields
|
---|
4830 | with <var class="LITERAL">new_field()</var>. new_field() takes
|
---|
4831 | height, width, starty, startx, number of offscreen rows and number
|
---|
4832 | of additional working buffers. The fifth argument number of
|
---|
4833 | offscreen rows specifies how much of the field to be shown. If it
|
---|
4834 | is zero, the entire field is always displayed otherwise the form
|
---|
4835 | will be scrollable when the user accesses not displayed parts of
|
---|
4836 | the field. The forms library allocates one buffer per field to
|
---|
4837 | store the data user enters. Using the last parameter to new_field()
|
---|
4838 | we can specify it to allocate some additional buffers. These can be
|
---|
4839 | used for any purpose you like.</p>
|
---|
4840 | <p>After creating the fields, back ground attribute of both of them
|
---|
4841 | is set to an underscore with set_field_back(). The AUTOSKIP option
|
---|
4842 | is turned off using field_opts_off(). If this option is turned on,
|
---|
4843 | focus will move to the next field in the form once the active field
|
---|
4844 | is filled up completely.</p>
|
---|
4845 | <p>After attaching the fields to the form, it is posted. Here on,
|
---|
4846 | user inputs are processed in the while loop, by making
|
---|
4847 | corresponding requests to form_driver. The details of all the
|
---|
4848 | requests to the form_driver() are explained later.</p>
|
---|
4849 | </div>
|
---|
4850 | <div class="SECT2">
|
---|
4851 | <hr>
|
---|
4852 | <h3 class="SECT2"><a name="PLAYFIELDS" id="PLAYFIELDS">18.3.
|
---|
4853 | Playing with Fields</a></h3>
|
---|
4854 | <p>Each form field is associated with a lot of attributes. They can
|
---|
4855 | be manipulated to get the required effect and to have fun !!!. So
|
---|
4856 | why wait?</p>
|
---|
4857 | <div class="SECT3">
|
---|
4858 | <hr>
|
---|
4859 | <h4 class="SECT3"><a name="FETCHINFO" id="FETCHINFO">18.3.1.
|
---|
4860 | Fetching Size and Location of Field</a></h4>
|
---|
4861 | <p>The parameters we have given at the time of creation of a field
|
---|
4862 | can be retrieved with field_info(). It returns height, width,
|
---|
4863 | starty, startx, number of offscreen rows, and number of additional
|
---|
4864 | buffers into the parameters given to it. It is a sort of inverse of
|
---|
4865 | new_field().</p>
|
---|
4866 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
4867 | <tr>
|
---|
4868 | <td>
|
---|
4869 | <pre class="PROGRAMLISTING">
|
---|
4870 | <font color=
|
---|
4871 | "#000000">int field_info( FIELD *field, /* field from which to fetch */
|
---|
4872 | int *height, *int width, /* field size */
|
---|
4873 | int *top, int *left, /* upper left corner */
|
---|
4874 | int *offscreen, /* number of offscreen rows */
|
---|
4875 | int *nbuf); /* number of working buffers */</font>
|
---|
4876 | </pre></td>
|
---|
4877 | </tr>
|
---|
4878 | </table>
|
---|
4879 | </div>
|
---|
4880 | <div class="SECT3">
|
---|
4881 | <hr>
|
---|
4882 | <h4 class="SECT3"><a name="MOVEFIELD" id="MOVEFIELD">18.3.2. Moving
|
---|
4883 | the field</a></h4>
|
---|
4884 | <p>The location of the field can be moved to a different position
|
---|
4885 | with move_field().</p>
|
---|
4886 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
4887 | <tr>
|
---|
4888 | <td>
|
---|
4889 | <pre class="PROGRAMLISTING">
|
---|
4890 | <font color=
|
---|
4891 | "#000000">int move_field( FIELD *field, /* field to alter */
|
---|
4892 | int top, int left); /* new upper-left corner */</font>
|
---|
4893 | </pre></td>
|
---|
4894 | </tr>
|
---|
4895 | </table>
|
---|
4896 | <p>As usual, the changed position can be queried with
|
---|
4897 | field_infor().</p>
|
---|
4898 | </div>
|
---|
4899 | <div class="SECT3">
|
---|
4900 | <hr>
|
---|
4901 | <h4 class="SECT3"><a name="JUSTIFYFIELD" id="JUSTIFYFIELD">18.3.3.
|
---|
4902 | Field Justification</a></h4>
|
---|
4903 | <p>The justification to be done for the field can be fixed using
|
---|
4904 | the function set_field_just().</p>
|
---|
4905 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
4906 | <tr>
|
---|
4907 | <td>
|
---|
4908 | <pre class="PROGRAMLISTING">
|
---|
4909 | <font color=
|
---|
4910 | "#000000"> int set_field_just(FIELD *field, /* field to alter */
|
---|
4911 | int justmode); /* mode to set */
|
---|
4912 | int field_just(FIELD *field); /* fetch justify mode of field */</font>
|
---|
4913 | </pre></td>
|
---|
4914 | </tr>
|
---|
4915 | </table>
|
---|
4916 | <p>The justification mode valued accepted and returned by these
|
---|
4917 | functions are NO_JUSTIFICATION, JUSTIFY_RIGHT, JUSTIFY_LEFT, or
|
---|
4918 | JUSTIFY_CENTER.</p>
|
---|
4919 | </div>
|
---|
4920 | <div class="SECT3">
|
---|
4921 | <hr>
|
---|
4922 | <h4 class="SECT3"><a name="FIELDDISPATTRIB" id=
|
---|
4923 | "FIELDDISPATTRIB">18.3.4. Field Display Attributes</a></h4>
|
---|
4924 | <p>As you have seen, in the above example, display attribute for
|
---|
4925 | the fields can be set with set_field_fore() and setfield_back().
|
---|
4926 | These functions set foreground and background attribute of the
|
---|
4927 | fields. You can also specify a pad character which will be filled
|
---|
4928 | in the unfilled portion of the field. The pad character is set with
|
---|
4929 | a call to set_field_pad(). Default pad value is a space. The
|
---|
4930 | functions field_fore(), field_back, field_pad() can be used to
|
---|
4931 | query the present foreground, background attributes and pad
|
---|
4932 | character for the field. The following list gives the usage of
|
---|
4933 | functions.</p>
|
---|
4934 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
4935 | <tr>
|
---|
4936 | <td>
|
---|
4937 | <pre class="PROGRAMLISTING">
|
---|
4938 | <font color=
|
---|
4939 | "#000000"> int set_field_fore(FIELD *field, /* field to alter */
|
---|
4940 | chtype attr); /* attribute to set */
|
---|
4941 |
|
---|
4942 | chtype field_fore(FIELD *field); /* field to query */
|
---|
4943 | /* returns foreground attribute */
|
---|
4944 |
|
---|
4945 | int set_field_back(FIELD *field, /* field to alter */
|
---|
4946 | chtype attr); /* attribute to set */
|
---|
4947 |
|
---|
4948 | chtype field_back(FIELD *field); /* field to query */
|
---|
4949 | /* returns background attribute */
|
---|
4950 |
|
---|
4951 | int set_field_pad(FIELD *field, /* field to alter */
|
---|
4952 | int pad); /* pad character to set */
|
---|
4953 |
|
---|
4954 | chtype field_pad(FIELD *field); /* field to query */
|
---|
4955 | /* returns present pad character */ </font>
|
---|
4956 | </pre></td>
|
---|
4957 | </tr>
|
---|
4958 | </table>
|
---|
4959 | <p>Though above functions seem quite simple, using colors with
|
---|
4960 | set_field_fore() may be frustrating in the beginning. Let me first
|
---|
4961 | explain about foreground and background attributes of a field. The
|
---|
4962 | foreground attribute is associated with the character. That means a
|
---|
4963 | character in the field is printed with the attribute you have set
|
---|
4964 | with set_field_fore(). Background attribute is the attribute used
|
---|
4965 | to fill background of field, whether any character is there or not.
|
---|
4966 | So what about colors? Since colors are always defined in pairs,
|
---|
4967 | what is the right way to display colored fields? Here's an example
|
---|
4968 | clarifying color attributes.</p>
|
---|
4969 | <div class="EXAMPLE"><a name="FFOAT" id="FFOAT"></a>
|
---|
4970 | <p><b>Example 26. Form Attributes example</b></p>
|
---|
4971 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
4972 | <tr>
|
---|
4973 | <td>
|
---|
4974 | <pre class="PROGRAMLISTING">
|
---|
4975 | <font color="#000000"><span class=
|
---|
4976 | "INLINEMEDIAOBJECT">#include <form.h>
|
---|
4977 |
|
---|
4978 | int main()
|
---|
4979 | { FIELD *field[3];
|
---|
4980 | FORM *my_form;
|
---|
4981 | int ch;
|
---|
4982 |
|
---|
4983 | /* Initialize curses */
|
---|
4984 | initscr();
|
---|
4985 | start_color();
|
---|
4986 | cbreak();
|
---|
4987 | noecho();
|
---|
4988 | keypad(stdscr, TRUE);
|
---|
4989 |
|
---|
4990 | /* Initialize few color pairs */
|
---|
4991 | init_pair(1, COLOR_WHITE, COLOR_BLUE);
|
---|
4992 | init_pair(2, COLOR_WHITE, COLOR_BLUE);
|
---|
4993 |
|
---|
4994 | /* Initialize the fields */
|
---|
4995 | field[0] = new_field(1, 10, 4, 18, 0, 0);
|
---|
4996 | field[1] = new_field(1, 10, 6, 18, 0, 0);
|
---|
4997 | field[2] = NULL;
|
---|
4998 |
|
---|
4999 | /* Set field options */
|
---|
5000 | set_field_fore(field[0], COLOR_PAIR(1));/* Put the field with blue background */
|
---|
5001 | set_field_back(field[0], COLOR_PAIR(2));/* and white foreground (characters */
|
---|
5002 | /* are printed in white */
|
---|
5003 | field_opts_off(field[0], O_AUTOSKIP); /* Don't go to next field when this */
|
---|
5004 | /* Field is filled up */
|
---|
5005 | set_field_back(field[1], A_UNDERLINE);
|
---|
5006 | field_opts_off(field[1], O_AUTOSKIP);
|
---|
5007 |
|
---|
5008 | /* Create the form and post it */
|
---|
5009 | my_form = new_form(field);
|
---|
5010 | post_form(my_form);
|
---|
5011 | refresh();
|
---|
5012 |
|
---|
5013 | set_current_field(my_form, field[0]); /* Set focus to the colored field */
|
---|
5014 | mvprintw(4, 10, "Value 1:");
|
---|
5015 | mvprintw(6, 10, "Value 2:");
|
---|
5016 | mvprintw(LINES - 2, 0, "Use UP, DOWN arrow keys to switch between fields");
|
---|
5017 | refresh();
|
---|
5018 |
|
---|
5019 | /* Loop through to get user requests */
|
---|
5020 | while((ch = getch()) != KEY_F(1))
|
---|
5021 | { switch(ch)
|
---|
5022 | { case KEY_DOWN:
|
---|
5023 | /* Go to next field */
|
---|
5024 | form_driver(my_form, REQ_NEXT_FIELD);
|
---|
5025 | /* Go to the end of the present buffer */
|
---|
5026 | /* Leaves nicely at the last character */
|
---|
5027 | form_driver(my_form, REQ_END_LINE);
|
---|
5028 | break;
|
---|
5029 | case KEY_UP:
|
---|
5030 | /* Go to previous field */
|
---|
5031 | form_driver(my_form, REQ_PREV_FIELD);
|
---|
5032 | form_driver(my_form, REQ_END_LINE);
|
---|
5033 | break;
|
---|
5034 | default:
|
---|
5035 | /* If this is a normal character, it gets */
|
---|
5036 | /* Printed */
|
---|
5037 | form_driver(my_form, ch);
|
---|
5038 | break;
|
---|
5039 | }
|
---|
5040 | }
|
---|
5041 |
|
---|
5042 | /* Un post form and free the memory */
|
---|
5043 | unpost_form(my_form);
|
---|
5044 | free_form(my_form);
|
---|
5045 | free_field(field[0]);
|
---|
5046 | free_field(field[1]);
|
---|
5047 |
|
---|
5048 | endwin();
|
---|
5049 | return 0;
|
---|
5050 | }</span></font>
|
---|
5051 | </pre></td>
|
---|
5052 | </tr>
|
---|
5053 | </table>
|
---|
5054 | </div>
|
---|
5055 | <p>Play with the color pairs and try to understand the foreground
|
---|
5056 | and background attributes. In my programs using color attributes, I
|
---|
5057 | usually set only the background with set_field_back(). Curses
|
---|
5058 | simply doesn't allow defining individual color attributes.</p>
|
---|
5059 | </div>
|
---|
5060 | <div class="SECT3">
|
---|
5061 | <hr>
|
---|
5062 | <h4 class="SECT3"><a name="FIELDOPTIONBITS" id=
|
---|
5063 | "FIELDOPTIONBITS">18.3.5. Field Option Bits</a></h4>
|
---|
5064 | <p>There is also a large collection of field option bits you can
|
---|
5065 | set to control various aspects of forms processing. You can
|
---|
5066 | manipulate them with these functions:</p>
|
---|
5067 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
5068 | <tr>
|
---|
5069 | <td>
|
---|
5070 | <pre class="PROGRAMLISTING">
|
---|
5071 | <font color=
|
---|
5072 | "#000000">int set_field_opts(FIELD *field, /* field to alter */
|
---|
5073 | int attr); /* attribute to set */
|
---|
5074 |
|
---|
5075 | int field_opts_on(FIELD *field, /* field to alter */
|
---|
5076 | int attr); /* attributes to turn on */
|
---|
5077 |
|
---|
5078 | int field_opts_off(FIELD *field, /* field to alter */
|
---|
5079 | int attr); /* attributes to turn off */
|
---|
5080 |
|
---|
5081 | int field_opts(FIELD *field); /* field to query */ </font>
|
---|
5082 | </pre></td>
|
---|
5083 | </tr>
|
---|
5084 | </table>
|
---|
5085 | <p>The function set_field_opts() can be used to directly set
|
---|
5086 | attributes of a field or you can choose to switch a few attributes
|
---|
5087 | on and off with field_opts_on() and field_opts_off() selectively.
|
---|
5088 | Anytime you can query the attributes of a field with field_opts().
|
---|
5089 | The following is the list of available options. By default, all
|
---|
5090 | options are on.</p>
|
---|
5091 | <div class="VARIABLELIST">
|
---|
5092 | <dl>
|
---|
5093 | <dt>O_VISIBLE</dt>
|
---|
5094 | <dd>
|
---|
5095 | <p>Controls whether the field is visible on the screen. Can be used
|
---|
5096 | during form processing to hide or pop up fields depending on the
|
---|
5097 | value of parent fields.</p>
|
---|
5098 | </dd>
|
---|
5099 | <dt>O_ACTIVE</dt>
|
---|
5100 | <dd>
|
---|
5101 | <p>Controls whether the field is active during forms processing
|
---|
5102 | (i.e. visited by form navigation keys). Can be used to make labels
|
---|
5103 | or derived fields with buffer values alterable by the forms
|
---|
5104 | application, not the user.</p>
|
---|
5105 | </dd>
|
---|
5106 | <dt>O_PUBLIC</dt>
|
---|
5107 | <dd>
|
---|
5108 | <p>Controls whether data is displayed during field entry. If this
|
---|
5109 | option is turned off on a field, the library will accept and edit
|
---|
5110 | data in that field, but it will not be displayed and the visible
|
---|
5111 | field cursor will not move. You can turn off the O_PUBLIC bit to
|
---|
5112 | define password fields.</p>
|
---|
5113 | </dd>
|
---|
5114 | <dt>O_EDIT</dt>
|
---|
5115 | <dd>
|
---|
5116 | <p>Controls whether the field's data can be modified. When this
|
---|
5117 | option is off, all editing requests except <var class=
|
---|
5118 | "LITERAL">REQ_PREV_CHOICE</var> and <var class=
|
---|
5119 | "LITERAL">REQ_NEXT_CHOICE</var>will fail. Such read-only fields may
|
---|
5120 | be useful for help messages.</p>
|
---|
5121 | </dd>
|
---|
5122 | <dt>O_WRAP</dt>
|
---|
5123 | <dd>
|
---|
5124 | <p>Controls word-wrapping in multi-line fields. Normally, when any
|
---|
5125 | character of a (blank-separated) word reaches the end of the
|
---|
5126 | current line, the entire word is wrapped to the next line (assuming
|
---|
5127 | there is one). When this option is off, the word will be split
|
---|
5128 | across the line break.</p>
|
---|
5129 | </dd>
|
---|
5130 | <dt>O_BLANK</dt>
|
---|
5131 | <dd>
|
---|
5132 | <p>Controls field blanking. When this option is on, entering a
|
---|
5133 | character at the first field position erases the entire field
|
---|
5134 | (except for the just-entered character).</p>
|
---|
5135 | </dd>
|
---|
5136 | <dt>O_AUTOSKIP</dt>
|
---|
5137 | <dd>
|
---|
5138 | <p>Controls automatic skip to next field when this one fills.
|
---|
5139 | Normally, when the forms user tries to type more data into a field
|
---|
5140 | than will fit, the editing location jumps to next field. When this
|
---|
5141 | option is off, the user's cursor will hang at the end of the field.
|
---|
5142 | This option is ignored in dynamic fields that have not reached
|
---|
5143 | their size limit.</p>
|
---|
5144 | </dd>
|
---|
5145 | <dt>O_NULLOK</dt>
|
---|
5146 | <dd>
|
---|
5147 | <p>Controls whether validation is applied to blank fields.
|
---|
5148 | Normally, it is not; the user can leave a field blank without
|
---|
5149 | invoking the usual validation check on exit. If this option is off
|
---|
5150 | on a field, exit from it will invoke a validation check.</p>
|
---|
5151 | </dd>
|
---|
5152 | <dt>O_PASSOK</dt>
|
---|
5153 | <dd>
|
---|
5154 | <p>Controls whether validation occurs on every exit, or only after
|
---|
5155 | the field is modified. Normally the latter is true. Setting
|
---|
5156 | O_PASSOK may be useful if your field's validation function may
|
---|
5157 | change during forms processing.</p>
|
---|
5158 | </dd>
|
---|
5159 | <dt>O_STATIC</dt>
|
---|
5160 | <dd>
|
---|
5161 | <p>Controls whether the field is fixed to its initial dimensions.
|
---|
5162 | If you turn this off, the field becomes dynamic and will stretch to
|
---|
5163 | fit entered data.</p>
|
---|
5164 | </dd>
|
---|
5165 | </dl>
|
---|
5166 | </div>
|
---|
5167 | <p>A field's options cannot be changed while the field is currently
|
---|
5168 | selected. However, options may be changed on posted fields that are
|
---|
5169 | not current.</p>
|
---|
5170 | <p>The option values are bit-masks and can be composed with
|
---|
5171 | logical-or in the obvious way. You have seen the usage of switching
|
---|
5172 | off O_AUTOSKIP option. The following example clarifies usage of
|
---|
5173 | some more options. Other options are explained where
|
---|
5174 | appropriate.</p>
|
---|
5175 | <div class="EXAMPLE"><a name="FFOOP" id="FFOOP"></a>
|
---|
5176 | <p><b>Example 27. Field Options Usage example</b></p>
|
---|
5177 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
5178 | <tr>
|
---|
5179 | <td>
|
---|
5180 | <pre class="PROGRAMLISTING">
|
---|
5181 | <font color="#000000"><span class=
|
---|
5182 | "INLINEMEDIAOBJECT">#include <form.h>
|
---|
5183 |
|
---|
5184 | #define STARTX 15
|
---|
5185 | #define STARTY 4
|
---|
5186 | #define WIDTH 25
|
---|
5187 |
|
---|
5188 | #define N_FIELDS 3
|
---|
5189 |
|
---|
5190 | int main()
|
---|
5191 | { FIELD *field[N_FIELDS];
|
---|
5192 | FORM *my_form;
|
---|
5193 | int ch, i;
|
---|
5194 |
|
---|
5195 | /* Initialize curses */
|
---|
5196 | initscr();
|
---|
5197 | cbreak();
|
---|
5198 | noecho();
|
---|
5199 | keypad(stdscr, TRUE);
|
---|
5200 |
|
---|
5201 | /* Initialize the fields */
|
---|
5202 | for(i = 0; i < N_FIELDS - 1; ++i)
|
---|
5203 | field[i] = new_field(1, WIDTH, STARTY + i * 2, STARTX, 0, 0);
|
---|
5204 | field[N_FIELDS - 1] = NULL;
|
---|
5205 |
|
---|
5206 | /* Set field options */
|
---|
5207 | set_field_back(field[1], A_UNDERLINE); /* Print a line for the option */
|
---|
5208 |
|
---|
5209 | field_opts_off(field[0], O_ACTIVE); /* This field is a static label */
|
---|
5210 | field_opts_off(field[1], O_PUBLIC); /* This filed is like a password field*/
|
---|
5211 | field_opts_off(field[1], O_AUTOSKIP); /* To avoid entering the same field */
|
---|
5212 | /* after last character is entered */
|
---|
5213 |
|
---|
5214 | /* Create the form and post it */
|
---|
5215 | my_form = new_form(field);
|
---|
5216 | post_form(my_form);
|
---|
5217 | refresh();
|
---|
5218 |
|
---|
5219 | set_field_just(field[0], JUSTIFY_CENTER); /* Center Justification */
|
---|
5220 | set_field_buffer(field[0], 0, "This is a static Field");
|
---|
5221 | /* Initialize the field */
|
---|
5222 | mvprintw(STARTY, STARTX - 10, "Field 1:");
|
---|
5223 | mvprintw(STARTY + 2, STARTX - 10, "Field 2:");
|
---|
5224 | refresh();
|
---|
5225 |
|
---|
5226 | /* Loop through to get user requests */
|
---|
5227 | while((ch = getch()) != KEY_F(1))
|
---|
5228 | { switch(ch)
|
---|
5229 | { case KEY_DOWN:
|
---|
5230 | /* Go to next field */
|
---|
5231 | form_driver(my_form, REQ_NEXT_FIELD);
|
---|
5232 | /* Go to the end of the present buffer */
|
---|
5233 | /* Leaves nicely at the last character */
|
---|
5234 | form_driver(my_form, REQ_END_LINE);
|
---|
5235 | break;
|
---|
5236 | case KEY_UP:
|
---|
5237 | /* Go to previous field */
|
---|
5238 | form_driver(my_form, REQ_PREV_FIELD);
|
---|
5239 | form_driver(my_form, REQ_END_LINE);
|
---|
5240 | break;
|
---|
5241 | default:
|
---|
5242 | /* If this is a normal character, it gets */
|
---|
5243 | /* Printed */
|
---|
5244 | form_driver(my_form, ch);
|
---|
5245 | break;
|
---|
5246 | }
|
---|
5247 | }
|
---|
5248 |
|
---|
5249 | /* Un post form and free the memory */
|
---|
5250 | unpost_form(my_form);
|
---|
5251 | free_form(my_form);
|
---|
5252 | free_field(field[0]);
|
---|
5253 | free_field(field[1]);
|
---|
5254 |
|
---|
5255 | endwin();
|
---|
5256 | return 0;
|
---|
5257 | }</span></font>
|
---|
5258 | </pre></td>
|
---|
5259 | </tr>
|
---|
5260 | </table>
|
---|
5261 | </div>
|
---|
5262 | <p>This example, though useless, shows the usage of options. If
|
---|
5263 | used properly, they can present information very effectively in a
|
---|
5264 | form. The second field being not O_PUBLIC, does not show the
|
---|
5265 | characters you are typing.</p>
|
---|
5266 | </div>
|
---|
5267 | <div class="SECT3">
|
---|
5268 | <hr>
|
---|
5269 | <h4 class="SECT3"><a name="FIELDSTATUS" id="FIELDSTATUS">18.3.6.
|
---|
5270 | Field Status</a></h4>
|
---|
5271 | <p>The field status specifies whether the field has got edited or
|
---|
5272 | not. It is initially set to FALSE and when user enters something
|
---|
5273 | and the data buffer gets modified it becomes TRUE. So a field's
|
---|
5274 | status can be queried to find out whether it has been modified or
|
---|
5275 | not. The following functions can assist in those operations.</p>
|
---|
5276 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
5277 | <tr>
|
---|
5278 | <td>
|
---|
5279 | <pre class="PROGRAMLISTING">
|
---|
5280 | <font color=
|
---|
5281 | "#000000">int set_field_status(FIELD *field, /* field to alter */
|
---|
5282 | int status); /* status to set */
|
---|
5283 |
|
---|
5284 | int field_status(FIELD *field); /* fetch status of field */</font>
|
---|
5285 | </pre></td>
|
---|
5286 | </tr>
|
---|
5287 | </table>
|
---|
5288 | <p>It's better to check the field's status only after after leaving
|
---|
5289 | the field, as data buffer might not have been updated yet as the
|
---|
5290 | validation is still due. To guarantee that right status is
|
---|
5291 | returned, call field_status() either (1) in the field's exit
|
---|
5292 | validation check routine, (2) from the field's or form's
|
---|
5293 | initialization or termination hooks, or (3) just after a
|
---|
5294 | REQ_VALIDATION request has been processed by the forms driver</p>
|
---|
5295 | </div>
|
---|
5296 | <div class="SECT3">
|
---|
5297 | <hr>
|
---|
5298 | <h4 class="SECT3"><a name="FIELDUSERPTR" id="FIELDUSERPTR">18.3.7.
|
---|
5299 | Field User Pointer</a></h4>
|
---|
5300 | <p>Every field structure contains one pointer that can be used by
|
---|
5301 | the user for various purposes. It is not touched by forms library
|
---|
5302 | and can be used for any purpose by the user. The following
|
---|
5303 | functions set and fetch user pointer.</p>
|
---|
5304 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
5305 | <tr>
|
---|
5306 | <td>
|
---|
5307 | <pre class="PROGRAMLISTING">
|
---|
5308 | <font color="#000000">int set_field_userptr(FIELD *field,
|
---|
5309 | char *userptr); /* the user pointer you wish to associate */
|
---|
5310 | /* with the field */
|
---|
5311 |
|
---|
5312 | char *field_userptr(FIELD *field); /* fetch user pointer of the field */</font>
|
---|
5313 | </pre></td>
|
---|
5314 | </tr>
|
---|
5315 | </table>
|
---|
5316 | </div>
|
---|
5317 | <div class="SECT3">
|
---|
5318 | <hr>
|
---|
5319 | <h4 class="SECT3"><a name="VARIABLESIZEFIELDS" id=
|
---|
5320 | "VARIABLESIZEFIELDS">18.3.8. Variable-Sized Fields</a></h4>
|
---|
5321 | <p>If you want a dynamically changing field with variable width,
|
---|
5322 | this is the feature you want to put to full use. This will allow
|
---|
5323 | the user to enter more data than the original size of the field and
|
---|
5324 | let the field grow. According to the field orientation it will
|
---|
5325 | scroll horizontally or vertically to incorporate the new data.</p>
|
---|
5326 | <p>To make a field dynamically growable, the option O_STATIC should
|
---|
5327 | be turned off. This can be done with a</p>
|
---|
5328 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
5329 | <tr>
|
---|
5330 | <td>
|
---|
5331 | <pre class="PROGRAMLISTING">
|
---|
5332 | <font color=
|
---|
5333 | "#000000"> field_opts_off(field_pointer, O_STATIC);</font>
|
---|
5334 | </pre></td>
|
---|
5335 | </tr>
|
---|
5336 | </table>
|
---|
5337 | <p>But it's usually not advisable to allow a field to grow
|
---|
5338 | infinitely. You can set a maximum limit to the growth of the field
|
---|
5339 | with</p>
|
---|
5340 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
5341 | <tr>
|
---|
5342 | <td>
|
---|
5343 | <pre class="PROGRAMLISTING">
|
---|
5344 | <font color=
|
---|
5345 | "#000000">int set_max_field(FIELD *field, /* Field on which to operate */
|
---|
5346 | int max_growth); /* maximum growth allowed for the field */</font>
|
---|
5347 | </pre></td>
|
---|
5348 | </tr>
|
---|
5349 | </table>
|
---|
5350 | <p>The field info for a dynamically growable field can be retrieved
|
---|
5351 | by</p>
|
---|
5352 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
5353 | <tr>
|
---|
5354 | <td>
|
---|
5355 | <pre class="PROGRAMLISTING">
|
---|
5356 | <font color=
|
---|
5357 | "#000000">int dynamic_field_info( FIELD *field, /* Field on which to operate */
|
---|
5358 | int *prows, /* number of rows will be filled in this */
|
---|
5359 | int *pcols, /* number of columns will be filled in this*/
|
---|
5360 | int *pmax) /* maximum allowable growth will be filled */
|
---|
5361 | /* in this */</font>
|
---|
5362 | </pre></td>
|
---|
5363 | </tr>
|
---|
5364 | </table>
|
---|
5365 | Though field_info work as usual, it is advisable to use this
|
---|
5366 | function to get the proper attributes of a dynamically growable
|
---|
5367 | field.
|
---|
5368 | <p>Recall the library routine new_field; a new field created with
|
---|
5369 | height set to one will be defined to be a one line field. A new
|
---|
5370 | field created with height greater than one will be defined to be a
|
---|
5371 | multi line field.</p>
|
---|
5372 | <p>A one line field with O_STATIC turned off (dynamically growable
|
---|
5373 | field) will contain a single fixed row, but the number of columns
|
---|
5374 | can increase if the user enters more data than the initial field
|
---|
5375 | will hold. The number of columns displayed will remain fixed and
|
---|
5376 | the additional data will scroll horizontally.</p>
|
---|
5377 | <p>A multi line field with O_STATIC turned off (dynamically
|
---|
5378 | growable field) will contain a fixed number of columns, but the
|
---|
5379 | number of rows can increase if the user enters more data than the
|
---|
5380 | initial field will hold. The number of rows displayed will remain
|
---|
5381 | fixed and the additional data will scroll vertically.</p>
|
---|
5382 | <p>The above two paragraphs pretty much describe a dynamically
|
---|
5383 | growable field's behavior. The way other parts of forms library
|
---|
5384 | behaves is described below:</p>
|
---|
5385 | <ol type="1">
|
---|
5386 | <li>
|
---|
5387 | <p>The field option O_AUTOSKIP will be ignored if the option
|
---|
5388 | O_STATIC is off and there is no maximum growth specified for the
|
---|
5389 | field. Currently, O_AUTOSKIP generates an automatic REQ_NEXT_FIELD
|
---|
5390 | form driver request when the user types in the last character
|
---|
5391 | position of a field. On a growable field with no maximum growth
|
---|
5392 | specified, there is no last character position. If a maximum growth
|
---|
5393 | is specified, the O_AUTOSKIP option will work as normal if the
|
---|
5394 | field has grown to its maximum size.</p>
|
---|
5395 | </li>
|
---|
5396 | <li>
|
---|
5397 | <p>The field justification will be ignored if the option O_STATIC
|
---|
5398 | is off. Currently, set_field_just can be used to JUSTIFY_LEFT,
|
---|
5399 | JUSTIFY_RIGHT, JUSTIFY_CENTER the contents of a one line field. A
|
---|
5400 | growable one line field will, by definition, grow and scroll
|
---|
5401 | horizontally and may contain more data than can be justified. The
|
---|
5402 | return from field_just will be unchanged.</p>
|
---|
5403 | </li>
|
---|
5404 | <li>
|
---|
5405 | <p>The overloaded form driver request REQ_NEW_LINE will operate the
|
---|
5406 | same way regardless of the O_NL_OVERLOAD form option if the field
|
---|
5407 | option O_STATIC is off and there is no maximum growth specified for
|
---|
5408 | the field. Currently, if the form option O_NL_OVERLOAD is on,
|
---|
5409 | REQ_NEW_LINE implicitly generates a REQ_NEXT_FIELD if called from
|
---|
5410 | the last line of a field. If a field can grow without bound, there
|
---|
5411 | is no last line, so REQ_NEW_LINE will never implicitly generate a
|
---|
5412 | REQ_NEXT_FIELD. If a maximum growth limit is specified and the
|
---|
5413 | O_NL_OVERLOAD form option is on, REQ_NEW_LINE will only implicitly
|
---|
5414 | generate REQ_NEXT_FIELD if the field has grown to its maximum size
|
---|
5415 | and the user is on the last line.</p>
|
---|
5416 | </li>
|
---|
5417 | <li>
|
---|
5418 | <p>The library call dup_field will work as usual; it will duplicate
|
---|
5419 | the field, including the current buffer size and contents of the
|
---|
5420 | field being duplicated. Any specified maximum growth will also be
|
---|
5421 | duplicated.</p>
|
---|
5422 | </li>
|
---|
5423 | <li>
|
---|
5424 | <p>The library call link_field will work as usual; it will
|
---|
5425 | duplicate all field attributes and share buffers with the field
|
---|
5426 | being linked. If the O_STATIC field option is subsequently changed
|
---|
5427 | by a field sharing buffers, how the system reacts to an attempt to
|
---|
5428 | enter more data into the field than the buffer will currently hold
|
---|
5429 | will depend on the setting of the option in the current field.</p>
|
---|
5430 | </li>
|
---|
5431 | <li>
|
---|
5432 | <p>The library call field_info will work as usual; the variable
|
---|
5433 | nrow will contain the value of the original call to new_field. The
|
---|
5434 | user should use dynamic_field_info, described above, to query the
|
---|
5435 | current size of the buffer.</p>
|
---|
5436 | </li>
|
---|
5437 | </ol>
|
---|
5438 | <p>Some of the above points make sense only after explaining form
|
---|
5439 | driver. We will be looking into that in next few sections.</p>
|
---|
5440 | </div>
|
---|
5441 | </div>
|
---|
5442 | <div class="SECT2">
|
---|
5443 | <hr>
|
---|
5444 | <h3 class="SECT2"><a name="FORMWINDOWS" id="FORMWINDOWS">18.4. Form
|
---|
5445 | Windows</a></h3>
|
---|
5446 | <p>The form windows concept is pretty much similar to menu windows.
|
---|
5447 | Every form is associated with a main window and a sub window. The
|
---|
5448 | form main window displays any title or border associated or
|
---|
5449 | whatever the user wishes. Then the sub window contains all the
|
---|
5450 | fields and displays them according to their position. This gives
|
---|
5451 | the flexibility of manipulating fancy form displaying very
|
---|
5452 | easily.</p>
|
---|
5453 | <p>Since this is pretty much similar to menu windows, I am
|
---|
5454 | providing an example with out much explanation. The functions are
|
---|
5455 | similar and they work the same way.</p>
|
---|
5456 | <div class="EXAMPLE"><a name="FFOWI" id="FFOWI"></a>
|
---|
5457 | <p><b>Example 28. Form Windows Example</b></p>
|
---|
5458 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
5459 | <tr>
|
---|
5460 | <td>
|
---|
5461 | <pre class="PROGRAMLISTING">
|
---|
5462 | <font color="#000000"><span class=
|
---|
5463 | "INLINEMEDIAOBJECT">#include <form.h>
|
---|
5464 |
|
---|
5465 | void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color);
|
---|
5466 |
|
---|
5467 | int main()
|
---|
5468 | {
|
---|
5469 | FIELD *field[3];
|
---|
5470 | FORM *my_form;
|
---|
5471 | WINDOW *my_form_win;
|
---|
5472 | int ch, rows, cols;
|
---|
5473 |
|
---|
5474 | /* Initialize curses */
|
---|
5475 | initscr();
|
---|
5476 | start_color();
|
---|
5477 | cbreak();
|
---|
5478 | noecho();
|
---|
5479 | keypad(stdscr, TRUE);
|
---|
5480 |
|
---|
5481 | /* Initialize few color pairs */
|
---|
5482 | init_pair(1, COLOR_RED, COLOR_BLACK);
|
---|
5483 |
|
---|
5484 | /* Initialize the fields */
|
---|
5485 | field[0] = new_field(1, 10, 6, 1, 0, 0);
|
---|
5486 | field[1] = new_field(1, 10, 8, 1, 0, 0);
|
---|
5487 | field[2] = NULL;
|
---|
5488 |
|
---|
5489 | /* Set field options */
|
---|
5490 | set_field_back(field[0], A_UNDERLINE);
|
---|
5491 | field_opts_off(field[0], O_AUTOSKIP); /* Don't go to next field when this */
|
---|
5492 | /* Field is filled up */
|
---|
5493 | set_field_back(field[1], A_UNDERLINE);
|
---|
5494 | field_opts_off(field[1], O_AUTOSKIP);
|
---|
5495 |
|
---|
5496 | /* Create the form and post it */
|
---|
5497 | my_form = new_form(field);
|
---|
5498 |
|
---|
5499 | /* Calculate the area required for the form */
|
---|
5500 | scale_form(my_form, &rows, &cols);
|
---|
5501 |
|
---|
5502 | /* Create the window to be associated with the form */
|
---|
5503 | my_form_win = newwin(rows + 4, cols + 4, 4, 4);
|
---|
5504 | keypad(my_form_win, TRUE);
|
---|
5505 |
|
---|
5506 | /* Set main window and sub window */
|
---|
5507 | set_form_win(my_form, my_form_win);
|
---|
5508 | set_form_sub(my_form, derwin(my_form_win, rows, cols, 2, 2));
|
---|
5509 |
|
---|
5510 | /* Print a border around the main window and print a title */
|
---|
5511 | box(my_form_win, 0, 0);
|
---|
5512 | print_in_middle(my_form_win, 1, 0, cols + 4, "My Form", COLOR_PAIR(1));
|
---|
5513 |
|
---|
5514 | post_form(my_form);
|
---|
5515 | wrefresh(my_form_win);
|
---|
5516 |
|
---|
5517 | mvprintw(LINES - 2, 0, "Use UP, DOWN arrow keys to switch between fields");
|
---|
5518 | refresh();
|
---|
5519 |
|
---|
5520 | /* Loop through to get user requests */
|
---|
5521 | while((ch = wgetch(my_form_win)) != KEY_F(1))
|
---|
5522 | { switch(ch)
|
---|
5523 | { case KEY_DOWN:
|
---|
5524 | /* Go to next field */
|
---|
5525 | form_driver(my_form, REQ_NEXT_FIELD);
|
---|
5526 | /* Go to the end of the present buffer */
|
---|
5527 | /* Leaves nicely at the last character */
|
---|
5528 | form_driver(my_form, REQ_END_LINE);
|
---|
5529 | break;
|
---|
5530 | case KEY_UP:
|
---|
5531 | /* Go to previous field */
|
---|
5532 | form_driver(my_form, REQ_PREV_FIELD);
|
---|
5533 | form_driver(my_form, REQ_END_LINE);
|
---|
5534 | break;
|
---|
5535 | default:
|
---|
5536 | /* If this is a normal character, it gets */
|
---|
5537 | /* Printed */
|
---|
5538 | form_driver(my_form, ch);
|
---|
5539 | break;
|
---|
5540 | }
|
---|
5541 | }
|
---|
5542 |
|
---|
5543 | /* Un post form and free the memory */
|
---|
5544 | unpost_form(my_form);
|
---|
5545 | free_form(my_form);
|
---|
5546 | free_field(field[0]);
|
---|
5547 | free_field(field[1]);
|
---|
5548 |
|
---|
5549 | endwin();
|
---|
5550 | return 0;
|
---|
5551 | }
|
---|
5552 |
|
---|
5553 | void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color)
|
---|
5554 | { int length, x, y;
|
---|
5555 | float temp;
|
---|
5556 |
|
---|
5557 | if(win == NULL)
|
---|
5558 | win = stdscr;
|
---|
5559 | getyx(win, y, x);
|
---|
5560 | if(startx != 0)
|
---|
5561 | x = startx;
|
---|
5562 | if(starty != 0)
|
---|
5563 | y = starty;
|
---|
5564 | if(width == 0)
|
---|
5565 | width = 80;
|
---|
5566 |
|
---|
5567 | length = strlen(string);
|
---|
5568 | temp = (width - length)/ 2;
|
---|
5569 | x = startx + (int)temp;
|
---|
5570 | wattron(win, color);
|
---|
5571 | mvwprintw(win, y, x, "%s", string);
|
---|
5572 | wattroff(win, color);
|
---|
5573 | refresh();
|
---|
5574 | }</span></font>
|
---|
5575 | </pre></td>
|
---|
5576 | </tr>
|
---|
5577 | </table>
|
---|
5578 | </div>
|
---|
5579 | </div>
|
---|
5580 | <div class="SECT2">
|
---|
5581 | <hr>
|
---|
5582 | <h3 class="SECT2"><a name="FILEDVALIDATE" id="FILEDVALIDATE">18.5.
|
---|
5583 | Field Validation</a></h3>
|
---|
5584 | <p>By default, a field will accept any data input by the user. It
|
---|
5585 | is possible to attach validation to the field. Then any attempt by
|
---|
5586 | the user to leave the field, while it contains data that doesn't
|
---|
5587 | match the validation type will fail. Some validation types also
|
---|
5588 | have a character-validity check for each time a character is
|
---|
5589 | entered in the field.</p>
|
---|
5590 | <p>Validation can be attached to a field with the following
|
---|
5591 | function.</p>
|
---|
5592 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
5593 | <tr>
|
---|
5594 | <td>
|
---|
5595 | <pre class="PROGRAMLISTING">
|
---|
5596 | <font color=
|
---|
5597 | "#000000">int set_field_type(FIELD *field, /* field to alter */
|
---|
5598 | FIELDTYPE *ftype, /* type to associate */
|
---|
5599 | ...); /* additional arguments*/</font>
|
---|
5600 | </pre></td>
|
---|
5601 | </tr>
|
---|
5602 | </table>
|
---|
5603 | Once set, the validation type for a field can be queried with
|
---|
5604 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
5605 | <tr>
|
---|
5606 | <td>
|
---|
5607 | <pre class="PROGRAMLISTING">
|
---|
5608 | <font color=
|
---|
5609 | "#000000">FIELDTYPE *field_type(FIELD *field); /* field to query */</font>
|
---|
5610 | </pre></td>
|
---|
5611 | </tr>
|
---|
5612 | </table>
|
---|
5613 | <p>The form driver validates the data in a field only when data is
|
---|
5614 | entered by the end-user. Validation does not occur when</p>
|
---|
5615 | <ul>
|
---|
5616 | <li>
|
---|
5617 | <p>the application program changes the field value by calling
|
---|
5618 | set_field_buffer.</p>
|
---|
5619 | </li>
|
---|
5620 | <li>
|
---|
5621 | <p>linked field values are changed indirectly -- by changing the
|
---|
5622 | field to which they are linked</p>
|
---|
5623 | </li>
|
---|
5624 | </ul>
|
---|
5625 | <p>The following are the pre-defined validation types. You can also
|
---|
5626 | specify custom validation, though it's a bit tricky and
|
---|
5627 | cumbersome.</p>
|
---|
5628 | <h1 class="BRIDGEHEAD"><a name="AEN1069" id=
|
---|
5629 | "AEN1069"></a>TYPE_ALPHA</h1>
|
---|
5630 | <p>This field type accepts alphabetic data; no blanks, no digits,
|
---|
5631 | no special characters (this is checked at character-entry time). It
|
---|
5632 | is set up with:</p>
|
---|
5633 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
5634 | <tr>
|
---|
5635 | <td>
|
---|
5636 | <pre class="PROGRAMLISTING">
|
---|
5637 | <font color=
|
---|
5638 | "#000000">int set_field_type(FIELD *field, /* field to alter */
|
---|
5639 | TYPE_ALPHA, /* type to associate */
|
---|
5640 | int width); /* maximum width of field */</font>
|
---|
5641 | </pre></td>
|
---|
5642 | </tr>
|
---|
5643 | </table>
|
---|
5644 | <p>The width argument sets a minimum width of data. The user has to
|
---|
5645 | enter at-least width number of characters before he can leave the
|
---|
5646 | field. Typically you'll want to set this to the field width; if
|
---|
5647 | it's greater than the field width, the validation check will always
|
---|
5648 | fail. A minimum width of zero makes field completion optional.</p>
|
---|
5649 | <h1 class="BRIDGEHEAD"><a name="AEN1073" id=
|
---|
5650 | "AEN1073"></a>TYPE_ALNUM</h1>
|
---|
5651 | <p>This field type accepts alphabetic data and digits; no blanks,
|
---|
5652 | no special characters (this is checked at character-entry time). It
|
---|
5653 | is set up with:</p>
|
---|
5654 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
5655 | <tr>
|
---|
5656 | <td>
|
---|
5657 | <pre class="PROGRAMLISTING">
|
---|
5658 | <font color=
|
---|
5659 | "#000000">int set_field_type(FIELD *field, /* field to alter */
|
---|
5660 | TYPE_ALNUM, /* type to associate */
|
---|
5661 | int width); /* maximum width of field */</font>
|
---|
5662 | </pre></td>
|
---|
5663 | </tr>
|
---|
5664 | </table>
|
---|
5665 | <p>The width argument sets a minimum width of data. As with
|
---|
5666 | TYPE_ALPHA, typically you'll want to set this to the field width;
|
---|
5667 | if it's greater than the field width, the validation check will
|
---|
5668 | always fail. A minimum width of zero makes field completion
|
---|
5669 | optional.</p>
|
---|
5670 | <h1 class="BRIDGEHEAD"><a name="AEN1077" id=
|
---|
5671 | "AEN1077"></a>TYPE_ENUM</h1>
|
---|
5672 | <p>This type allows you to restrict a field's values to be among a
|
---|
5673 | specified set of string values (for example, the two-letter postal
|
---|
5674 | codes for U.S. states). It is set up with:</p>
|
---|
5675 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
5676 | <tr>
|
---|
5677 | <td>
|
---|
5678 | <pre class="PROGRAMLISTING">
|
---|
5679 | <font color=
|
---|
5680 | "#000000">int set_field_type(FIELD *field, /* field to alter */
|
---|
5681 | TYPE_ENUM, /* type to associate */
|
---|
5682 | char **valuelist; /* list of possible values */
|
---|
5683 | int checkcase; /* case-sensitive? */
|
---|
5684 | int checkunique); /* must specify uniquely? */</font>
|
---|
5685 | </pre></td>
|
---|
5686 | </tr>
|
---|
5687 | </table>
|
---|
5688 | <p>The valuelist parameter must point at a NULL-terminated list of
|
---|
5689 | valid strings. The checkcase argument, if true, makes comparison
|
---|
5690 | with the string case-sensitive.</p>
|
---|
5691 | <p>When the user exits a TYPE_ENUM field, the validation procedure
|
---|
5692 | tries to complete the data in the buffer to a valid entry. If a
|
---|
5693 | complete choice string has been entered, it is of course valid. But
|
---|
5694 | it is also possible to enter a prefix of a valid string and have it
|
---|
5695 | completed for you.</p>
|
---|
5696 | <p>By default, if you enter such a prefix and it matches more than
|
---|
5697 | one value in the string list, the prefix will be completed to the
|
---|
5698 | first matching value. But the checkunique argument, if true,
|
---|
5699 | requires prefix matches to be unique in order to be valid.</p>
|
---|
5700 | <p>The REQ_NEXT_CHOICE and REQ_PREV_CHOICE input requests can be
|
---|
5701 | particularly useful with these fields.</p>
|
---|
5702 | <h1 class="BRIDGEHEAD"><a name="AEN1084" id=
|
---|
5703 | "AEN1084"></a>TYPE_INTEGER</h1>
|
---|
5704 | <p>This field type accepts an integer. It is set up as follows:</p>
|
---|
5705 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
5706 | <tr>
|
---|
5707 | <td>
|
---|
5708 | <pre class="PROGRAMLISTING">
|
---|
5709 | <font color=
|
---|
5710 | "#000000">int set_field_type(FIELD *field, /* field to alter */
|
---|
5711 | TYPE_INTEGER, /* type to associate */
|
---|
5712 | int padding, /* # places to zero-pad to */
|
---|
5713 | int vmin, int vmax); /* valid range */</font>
|
---|
5714 | </pre></td>
|
---|
5715 | </tr>
|
---|
5716 | </table>
|
---|
5717 | <p>Valid characters consist of an optional leading minus and
|
---|
5718 | digits. The range check is performed on exit. If the range maximum
|
---|
5719 | is less than or equal to the minimum, the range is ignored.</p>
|
---|
5720 | <p>If the value passes its range check, it is padded with as many
|
---|
5721 | leading zero digits as necessary to meet the padding argument.</p>
|
---|
5722 | <p>A TYPE_INTEGER value buffer can conveniently be interpreted with
|
---|
5723 | the C library function atoi(3).</p>
|
---|
5724 | <h1 class="BRIDGEHEAD"><a name="AEN1090" id=
|
---|
5725 | "AEN1090"></a>TYPE_NUMERIC</h1>
|
---|
5726 | <p>This field type accepts a decimal number. It is set up as
|
---|
5727 | follows:</p>
|
---|
5728 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
5729 | <tr>
|
---|
5730 | <td>
|
---|
5731 | <pre class="PROGRAMLISTING">
|
---|
5732 | <font color=
|
---|
5733 | "#000000">int set_field_type(FIELD *field, /* field to alter */
|
---|
5734 | TYPE_NUMERIC, /* type to associate */
|
---|
5735 | int padding, /* # places of precision */
|
---|
5736 | int vmin, int vmax); /* valid range */</font>
|
---|
5737 | </pre></td>
|
---|
5738 | </tr>
|
---|
5739 | </table>
|
---|
5740 | <p>Valid characters consist of an optional leading minus and
|
---|
5741 | digits. possibly including a decimal point. The range check is
|
---|
5742 | performed on exit. If the range maximum is less than or equal to
|
---|
5743 | the minimum, the range is ignored.</p>
|
---|
5744 | <p>If the value passes its range check, it is padded with as many
|
---|
5745 | trailing zero digits as necessary to meet the padding argument.</p>
|
---|
5746 | <p>A TYPE_NUMERIC value buffer can conveniently be interpreted with
|
---|
5747 | the C library function atof(3).</p>
|
---|
5748 | <h1 class="BRIDGEHEAD"><a name="AEN1096" id=
|
---|
5749 | "AEN1096"></a>TYPE_REGEXP</h1>
|
---|
5750 | <p>This field type accepts data matching a regular expression. It
|
---|
5751 | is set up as follows:</p>
|
---|
5752 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
5753 | <tr>
|
---|
5754 | <td>
|
---|
5755 | <pre class="PROGRAMLISTING">
|
---|
5756 | <font color=
|
---|
5757 | "#000000">int set_field_type(FIELD *field, /* field to alter */
|
---|
5758 | TYPE_REGEXP, /* type to associate */
|
---|
5759 | char *regexp); /* expression to match */</font>
|
---|
5760 | </pre></td>
|
---|
5761 | </tr>
|
---|
5762 | </table>
|
---|
5763 | <p>The syntax for regular expressions is that of regcomp(3). The
|
---|
5764 | check for regular-expression match is performed on exit.</p>
|
---|
5765 | </div>
|
---|
5766 | <div class="SECT2">
|
---|
5767 | <hr>
|
---|
5768 | <h3 class="SECT2"><a name="FORMDRIVER" id="FORMDRIVER">18.6. Form
|
---|
5769 | Driver: The work horse of the forms system</a></h3>
|
---|
5770 | <p>As in the menu system, form_driver() plays a very important role
|
---|
5771 | in forms system. All types of requests to forms system should be
|
---|
5772 | funneled through form_driver().</p>
|
---|
5773 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
5774 | <tr>
|
---|
5775 | <td>
|
---|
5776 | <pre class="PROGRAMLISTING">
|
---|
5777 | <font color=
|
---|
5778 | "#000000">int form_driver(FORM *form, /* form on which to operate */
|
---|
5779 | int request) /* form request code */</font>
|
---|
5780 | </pre></td>
|
---|
5781 | </tr>
|
---|
5782 | </table>
|
---|
5783 | <p>As you have seen some of the examples above, you have to be in a
|
---|
5784 | loop looking for user input and then decide whether it's a field
|
---|
5785 | data or a form request. The form requests are then passed to
|
---|
5786 | form_driver() to do the work.</p>
|
---|
5787 | <p>The requests roughly can be divided into following categories.
|
---|
5788 | Different requests and their usage is explained below:</p>
|
---|
5789 | <div class="SECT3">
|
---|
5790 | <hr>
|
---|
5791 | <h4 class="SECT3"><a name="PAGENAVREQ" id="PAGENAVREQ">18.6.1. Page
|
---|
5792 | Navigation Requests</a></h4>
|
---|
5793 | <p>These requests cause page-level moves through the form,
|
---|
5794 | triggering display of a new form screen. A form can be made of
|
---|
5795 | multiple pages. If you have a big form with lot of fields and
|
---|
5796 | logical sections, then you can divide the form into pages. The
|
---|
5797 | function set_new_page() to set a new page at the field
|
---|
5798 | specified.</p>
|
---|
5799 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
5800 | <tr>
|
---|
5801 | <td>
|
---|
5802 | <pre class="PROGRAMLISTING">
|
---|
5803 | <font color=
|
---|
5804 | "#000000">int set_new_page(FIELD *field,/* Field at which page break to be set or unset */
|
---|
5805 | bool new_page_flag); /* should be TRUE to put a break */</font>
|
---|
5806 | </pre></td>
|
---|
5807 | </tr>
|
---|
5808 | </table>
|
---|
5809 | <p>The following requests allow you to move to different pages</p>
|
---|
5810 | <ul>
|
---|
5811 | <li>
|
---|
5812 | <p><em>REQ_NEXT_PAGE</em> Move to the next form page.</p>
|
---|
5813 | </li>
|
---|
5814 | <li>
|
---|
5815 | <p><em>REQ_PREV_PAGE</em> Move to the previous form page.</p>
|
---|
5816 | </li>
|
---|
5817 | <li>
|
---|
5818 | <p><em>REQ_FIRST_PAGE</em> Move to the first form page.</p>
|
---|
5819 | </li>
|
---|
5820 | <li>
|
---|
5821 | <p><em>REQ_LAST_PAGE</em> Move to the last form page.</p>
|
---|
5822 | </li>
|
---|
5823 | </ul>
|
---|
5824 | <p>These requests treat the list as cyclic; that is, REQ_NEXT_PAGE
|
---|
5825 | from the last page goes to the first, and REQ_PREV_PAGE from the
|
---|
5826 | first page goes to the last.</p>
|
---|
5827 | </div>
|
---|
5828 | <div class="SECT3">
|
---|
5829 | <hr>
|
---|
5830 | <h4 class="SECT3"><a name="INTERFIELDNAVREQ" id=
|
---|
5831 | "INTERFIELDNAVREQ">18.6.2. Inter-Field Navigation Requests</a></h4>
|
---|
5832 | <p>These requests handle navigation between fields on the same
|
---|
5833 | page.</p>
|
---|
5834 | <ul>
|
---|
5835 | <li>
|
---|
5836 | <p><em>REQ_NEXT_FIELD</em> Move to next field.</p>
|
---|
5837 | </li>
|
---|
5838 | <li>
|
---|
5839 | <p><em>REQ_PREV_FIELD</em> Move to previous field.</p>
|
---|
5840 | </li>
|
---|
5841 | <li>
|
---|
5842 | <p><em>REQ_FIRST_FIELD</em> Move to the first field.</p>
|
---|
5843 | </li>
|
---|
5844 | <li>
|
---|
5845 | <p><em>REQ_LAST_FIELD</em> Move to the last field.</p>
|
---|
5846 | </li>
|
---|
5847 | <li>
|
---|
5848 | <p><em>REQ_SNEXT_FIELD</em> Move to sorted next field.</p>
|
---|
5849 | </li>
|
---|
5850 | <li>
|
---|
5851 | <p><em>REQ_SPREV_FIELD</em> Move to sorted previous field.</p>
|
---|
5852 | </li>
|
---|
5853 | <li>
|
---|
5854 | <p><em>REQ_SFIRST_FIELD</em> Move to the sorted first field.</p>
|
---|
5855 | </li>
|
---|
5856 | <li>
|
---|
5857 | <p><em>REQ_SLAST_FIELD</em> Move to the sorted last field.</p>
|
---|
5858 | </li>
|
---|
5859 | <li>
|
---|
5860 | <p><em>REQ_LEFT_FIELD</em> Move left to field.</p>
|
---|
5861 | </li>
|
---|
5862 | <li>
|
---|
5863 | <p><em>REQ_RIGHT_FIELD</em> Move right to field.</p>
|
---|
5864 | </li>
|
---|
5865 | <li>
|
---|
5866 | <p><em>REQ_UP_FIELD</em> Move up to field.</p>
|
---|
5867 | </li>
|
---|
5868 | <li>
|
---|
5869 | <p><em>REQ_DOWN_FIELD</em> Move down to field.</p>
|
---|
5870 | </li>
|
---|
5871 | </ul>
|
---|
5872 | <p>These requests treat the list of fields on a page as cyclic;
|
---|
5873 | that is, REQ_NEXT_FIELD from the last field goes to the first, and
|
---|
5874 | REQ_PREV_FIELD from the first field goes to the last. The order of
|
---|
5875 | the fields for these (and the REQ_FIRST_FIELD and REQ_LAST_FIELD
|
---|
5876 | requests) is simply the order of the field pointers in the form
|
---|
5877 | array (as set up by new_form() or set_form_fields()</p>
|
---|
5878 | <p>It is also possible to traverse the fields as if they had been
|
---|
5879 | sorted in screen-position order, so the sequence goes left-to-right
|
---|
5880 | and top-to-bottom. To do this, use the second group of four
|
---|
5881 | sorted-movement requests.</p>
|
---|
5882 | <p>Finally, it is possible to move between fields using visual
|
---|
5883 | directions up, down, right, and left. To accomplish this, use the
|
---|
5884 | third group of four requests. Note, however, that the position of a
|
---|
5885 | form for purposes of these requests is its upper-left corner.</p>
|
---|
5886 | <p>For example, suppose you have a multi-line field B, and two
|
---|
5887 | single-line fields A and C on the same line with B, with A to the
|
---|
5888 | left of B and C to the right of B. A REQ_MOVE_RIGHT from A will go
|
---|
5889 | to B only if A, B, and C all share the same first line; otherwise
|
---|
5890 | it will skip over B to C.</p>
|
---|
5891 | </div>
|
---|
5892 | <div class="SECT3">
|
---|
5893 | <hr>
|
---|
5894 | <h4 class="SECT3"><a name="INTRAFIELDNAVREQ" id=
|
---|
5895 | "INTRAFIELDNAVREQ">18.6.3. Intra-Field Navigation Requests</a></h4>
|
---|
5896 | <p>These requests drive movement of the edit cursor within the
|
---|
5897 | currently selected field.</p>
|
---|
5898 | <ul>
|
---|
5899 | <li>
|
---|
5900 | <p><em>REQ_NEXT_CHAR</em> Move to next character.</p>
|
---|
5901 | </li>
|
---|
5902 | <li>
|
---|
5903 | <p><em>REQ_PREV_CHAR</em> Move to previous character.</p>
|
---|
5904 | </li>
|
---|
5905 | <li>
|
---|
5906 | <p><em>REQ_NEXT_LINE</em> Move to next line.</p>
|
---|
5907 | </li>
|
---|
5908 | <li>
|
---|
5909 | <p><em>REQ_PREV_LINE</em> Move to previous line.</p>
|
---|
5910 | </li>
|
---|
5911 | <li>
|
---|
5912 | <p><em>REQ_NEXT_WORD</em> Move to next word.</p>
|
---|
5913 | </li>
|
---|
5914 | <li>
|
---|
5915 | <p><em>REQ_PREV_WORD</em> Move to previous word.</p>
|
---|
5916 | </li>
|
---|
5917 | <li>
|
---|
5918 | <p><em>REQ_BEG_FIELD</em> Move to beginning of field.</p>
|
---|
5919 | </li>
|
---|
5920 | <li>
|
---|
5921 | <p><em>REQ_END_FIELD</em> Move to end of field.</p>
|
---|
5922 | </li>
|
---|
5923 | <li>
|
---|
5924 | <p><em>REQ_BEG_LINE</em> Move to beginning of line.</p>
|
---|
5925 | </li>
|
---|
5926 | <li>
|
---|
5927 | <p><em>REQ_END_LINE</em> Move to end of line.</p>
|
---|
5928 | </li>
|
---|
5929 | <li>
|
---|
5930 | <p><em>REQ_LEFT_CHAR</em> Move left in field.</p>
|
---|
5931 | </li>
|
---|
5932 | <li>
|
---|
5933 | <p><em>REQ_RIGHT_CHAR</em> Move right in field.</p>
|
---|
5934 | </li>
|
---|
5935 | <li>
|
---|
5936 | <p><em>REQ_UP_CHAR</em> Move up in field.</p>
|
---|
5937 | </li>
|
---|
5938 | <li>
|
---|
5939 | <p><em>REQ_DOWN_CHAR</em> Move down in field.</p>
|
---|
5940 | </li>
|
---|
5941 | </ul>
|
---|
5942 | <p>Each word is separated from the previous and next characters by
|
---|
5943 | whitespace. The commands to move to beginning and end of line or
|
---|
5944 | field look for the first or last non-pad character in their
|
---|
5945 | ranges.</p>
|
---|
5946 | </div>
|
---|
5947 | <div class="SECT3">
|
---|
5948 | <hr>
|
---|
5949 | <h4 class="SECT3"><a name="SCROLLREQ" id="SCROLLREQ">18.6.4.
|
---|
5950 | Scrolling Requests</a></h4>
|
---|
5951 | <p>Fields that are dynamic and have grown and fields explicitly
|
---|
5952 | created with offscreen rows are scrollable. One-line fields scroll
|
---|
5953 | horizontally; multi-line fields scroll vertically. Most scrolling
|
---|
5954 | is triggered by editing and intra-field movement (the library
|
---|
5955 | scrolls the field to keep the cursor visible). It is possible to
|
---|
5956 | explicitly request scrolling with the following requests:</p>
|
---|
5957 | <ul>
|
---|
5958 | <li>
|
---|
5959 | <p><em>REQ_SCR_FLINE</em> Scroll vertically forward a line.</p>
|
---|
5960 | </li>
|
---|
5961 | <li>
|
---|
5962 | <p><em>REQ_SCR_BLINE</em> Scroll vertically backward a line.</p>
|
---|
5963 | </li>
|
---|
5964 | <li>
|
---|
5965 | <p><em>REQ_SCR_FPAGE</em> Scroll vertically forward a page.</p>
|
---|
5966 | </li>
|
---|
5967 | <li>
|
---|
5968 | <p><em>REQ_SCR_BPAGE</em> Scroll vertically backward a page.</p>
|
---|
5969 | </li>
|
---|
5970 | <li>
|
---|
5971 | <p><em>REQ_SCR_FHPAGE</em> Scroll vertically forward half a
|
---|
5972 | page.</p>
|
---|
5973 | </li>
|
---|
5974 | <li>
|
---|
5975 | <p><em>REQ_SCR_BHPAGE</em> Scroll vertically backward half a
|
---|
5976 | page.</p>
|
---|
5977 | </li>
|
---|
5978 | <li>
|
---|
5979 | <p><em>REQ_SCR_FCHAR</em> Scroll horizontally forward a
|
---|
5980 | character.</p>
|
---|
5981 | </li>
|
---|
5982 | <li>
|
---|
5983 | <p><em>REQ_SCR_BCHAR</em> Scroll horizontally backward a
|
---|
5984 | character.</p>
|
---|
5985 | </li>
|
---|
5986 | <li>
|
---|
5987 | <p><em>REQ_SCR_HFLINE</em> Scroll horizontally one field width
|
---|
5988 | forward.</p>
|
---|
5989 | </li>
|
---|
5990 | <li>
|
---|
5991 | <p><em>REQ_SCR_HBLINE</em> Scroll horizontally one field width
|
---|
5992 | backward.</p>
|
---|
5993 | </li>
|
---|
5994 | <li>
|
---|
5995 | <p><em>REQ_SCR_HFHALF</em> Scroll horizontally one half field width
|
---|
5996 | forward.</p>
|
---|
5997 | </li>
|
---|
5998 | <li>
|
---|
5999 | <p><em>REQ_SCR_HBHALF</em> Scroll horizontally one half field width
|
---|
6000 | backward.</p>
|
---|
6001 | </li>
|
---|
6002 | </ul>
|
---|
6003 | <p>For scrolling purposes, a page of a field is the height of its
|
---|
6004 | visible part.</p>
|
---|
6005 | </div>
|
---|
6006 | <div class="SECT3">
|
---|
6007 | <hr>
|
---|
6008 | <h4 class="SECT3"><a name="EDITREQ" id="EDITREQ">18.6.5. Editing
|
---|
6009 | Requests</a></h4>
|
---|
6010 | <p>When you pass the forms driver an ASCII character, it is treated
|
---|
6011 | as a request to add the character to the field's data buffer.
|
---|
6012 | Whether this is an insertion or a replacement depends on the
|
---|
6013 | field's edit mode (insertion is the default.</p>
|
---|
6014 | <p>The following requests support editing the field and changing
|
---|
6015 | the edit mode:</p>
|
---|
6016 | <ul>
|
---|
6017 | <li>
|
---|
6018 | <p><em>REQ_INS_MODE</em> Set insertion mode.</p>
|
---|
6019 | </li>
|
---|
6020 | <li>
|
---|
6021 | <p><em>REQ_OVL_MODE</em> Set overlay mode.</p>
|
---|
6022 | </li>
|
---|
6023 | <li>
|
---|
6024 | <p><em>REQ_NEW_LINE</em> New line request (see below for
|
---|
6025 | explanation).</p>
|
---|
6026 | </li>
|
---|
6027 | <li>
|
---|
6028 | <p><em>REQ_INS_CHAR</em> Insert space at character location.</p>
|
---|
6029 | </li>
|
---|
6030 | <li>
|
---|
6031 | <p><em>REQ_INS_LINE</em> Insert blank line at character
|
---|
6032 | location.</p>
|
---|
6033 | </li>
|
---|
6034 | <li>
|
---|
6035 | <p><em>REQ_DEL_CHAR</em> Delete character at cursor.</p>
|
---|
6036 | </li>
|
---|
6037 | <li>
|
---|
6038 | <p><em>REQ_DEL_PREV</em> Delete previous word at cursor.</p>
|
---|
6039 | </li>
|
---|
6040 | <li>
|
---|
6041 | <p><em>REQ_DEL_LINE</em> Delete line at cursor.</p>
|
---|
6042 | </li>
|
---|
6043 | <li>
|
---|
6044 | <p><em>REQ_DEL_WORD</em> Delete word at cursor.</p>
|
---|
6045 | </li>
|
---|
6046 | <li>
|
---|
6047 | <p><em>REQ_CLR_EOL</em> Clear to end of line.</p>
|
---|
6048 | </li>
|
---|
6049 | <li>
|
---|
6050 | <p><em>REQ_CLR_EOF</em> Clear to end of field.</p>
|
---|
6051 | </li>
|
---|
6052 | <li>
|
---|
6053 | <p><em>REQ_CLR_FIELD</em> Clear entire field.</p>
|
---|
6054 | </li>
|
---|
6055 | </ul>
|
---|
6056 | <p>The behavior of the REQ_NEW_LINE and REQ_DEL_PREV requests is
|
---|
6057 | complicated and partly controlled by a pair of forms options. The
|
---|
6058 | special cases are triggered when the cursor is at the beginning of
|
---|
6059 | a field, or on the last line of the field.</p>
|
---|
6060 | <p>First, we consider REQ_NEW_LINE:</p>
|
---|
6061 | <p>The normal behavior of REQ_NEW_LINE in insert mode is to break
|
---|
6062 | the current line at the position of the edit cursor, inserting the
|
---|
6063 | portion of the current line after the cursor as a new line
|
---|
6064 | following the current and moving the cursor to the beginning of
|
---|
6065 | that new line (you may think of this as inserting a newline in the
|
---|
6066 | field buffer).</p>
|
---|
6067 | <p>The normal behavior of REQ_NEW_LINE in overlay mode is to clear
|
---|
6068 | the current line from the position of the edit cursor to end of
|
---|
6069 | line. The cursor is then moved to the beginning of the next
|
---|
6070 | line.</p>
|
---|
6071 | <p>However, REQ_NEW_LINE at the beginning of a field, or on the
|
---|
6072 | last line of a field, instead does a REQ_NEXT_FIELD. O_NL_OVERLOAD
|
---|
6073 | option is off, this special action is disabled.</p>
|
---|
6074 | <p>Now, let us consider REQ_DEL_PREV:</p>
|
---|
6075 | <p>The normal behavior of REQ_DEL_PREV is to delete the previous
|
---|
6076 | character. If insert mode is on, and the cursor is at the start of
|
---|
6077 | a line, and the text on that line will fit on the previous one, it
|
---|
6078 | instead appends the contents of the current line to the previous
|
---|
6079 | one and deletes the current line (you may think of this as deleting
|
---|
6080 | a newline from the field buffer).</p>
|
---|
6081 | <p>However, REQ_DEL_PREV at the beginning of a field is instead
|
---|
6082 | treated as a REQ_PREV_FIELD.</p>
|
---|
6083 | <p>If the O_BS_OVERLOAD option is off, this special action is
|
---|
6084 | disabled and the forms driver just returns E_REQUEST_DENIED.</p>
|
---|
6085 | </div>
|
---|
6086 | <div class="SECT3">
|
---|
6087 | <hr>
|
---|
6088 | <h4 class="SECT3"><a name="ORDERREQ" id="ORDERREQ">18.6.6. Order
|
---|
6089 | Requests</a></h4>
|
---|
6090 | <p>If the type of your field is ordered, and has associated
|
---|
6091 | functions for getting the next and previous values of the type from
|
---|
6092 | a given value, there are requests that can fetch that value into
|
---|
6093 | the field buffer:</p>
|
---|
6094 | <ul>
|
---|
6095 | <li>
|
---|
6096 | <p><em>REQ_NEXT_CHOICE</em> Place the successor value of the
|
---|
6097 | current value in the buffer.</p>
|
---|
6098 | </li>
|
---|
6099 | <li>
|
---|
6100 | <p><em>REQ_PREV_CHOICE</em> Place the predecessor value of the
|
---|
6101 | current value in the buffer.</p>
|
---|
6102 | </li>
|
---|
6103 | </ul>
|
---|
6104 | <p>Of the built-in field types, only TYPE_ENUM has built-in
|
---|
6105 | successor and predecessor functions. When you define a field type
|
---|
6106 | of your own (see Custom Validation Types), you can associate our
|
---|
6107 | own ordering functions.</p>
|
---|
6108 | </div>
|
---|
6109 | <div class="SECT3">
|
---|
6110 | <hr>
|
---|
6111 | <h4 class="SECT3"><a name="APPLICCOMMANDS" id=
|
---|
6112 | "APPLICCOMMANDS">18.6.7. Application Commands</a></h4>
|
---|
6113 | <p>Form requests are represented as integers above the curses value
|
---|
6114 | greater than KEY_MAX and less than or equal to the constant
|
---|
6115 | MAX_COMMAND. A value within this range gets ignored by
|
---|
6116 | form_driver(). So this can be used for any purpose by the
|
---|
6117 | application. It can be treated as an application specific action
|
---|
6118 | and take corresponding action.</p>
|
---|
6119 | </div>
|
---|
6120 | </div>
|
---|
6121 | </div>
|
---|
6122 | <div class="SECT1">
|
---|
6123 | <hr>
|
---|
6124 | <h2 class="SECT1"><a name="TOOLS" id="TOOLS">19. Tools and Widget
|
---|
6125 | Libraries</a></h2>
|
---|
6126 | <p>Now that you have seen the capabilities of ncurses and its
|
---|
6127 | sister libraries, you are rolling your sleeves up and gearing for a
|
---|
6128 | project that heavily manipulates screen. But wait.. It can be
|
---|
6129 | pretty difficult to write and maintain complex GUI widgets in plain
|
---|
6130 | ncurses or even with the additional libraries. There are some
|
---|
6131 | ready-to-use tools and widget libraries that can be used instead of
|
---|
6132 | writing your own widgets. You can use some of them, get ideas from
|
---|
6133 | the code, or even extend them.</p>
|
---|
6134 | <div class="SECT2">
|
---|
6135 | <hr>
|
---|
6136 | <h3 class="SECT2"><a name="CDK" id="CDK">19.1. CDK (Curses
|
---|
6137 | Development Kit)</a></h3>
|
---|
6138 | <p>In the author's words</p>
|
---|
6139 | <p><em>CDK stands for 'Curses Development Kit' and it currently
|
---|
6140 | contains 21 ready to use widgets which facilitate the speedy
|
---|
6141 | development of full screen curses programs.</em></p>
|
---|
6142 | <p>The kit provides some useful widgets, which can be used in your
|
---|
6143 | programs directly. It's pretty well written and the documentation
|
---|
6144 | is very good. The examples in the examples directory can be a good
|
---|
6145 | place to start for beginners. The CDK can be downloaded from
|
---|
6146 | <a href="http://invisible-island.net/cdk/" target=
|
---|
6147 | "_top">http://invisible-island.net/cdk/</a> . Follow the
|
---|
6148 | instructions in README file to install it.</p>
|
---|
6149 | <div class="SECT3">
|
---|
6150 | <hr>
|
---|
6151 | <h4 class="SECT3"><a name="WIDGETLIST" id="WIDGETLIST">19.1.1.
|
---|
6152 | Widget List</a></h4>
|
---|
6153 | <p>The following is the list of widgets provided with cdk and their
|
---|
6154 | description.</p>
|
---|
6155 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
6156 | <tr>
|
---|
6157 | <td>
|
---|
6158 | <pre class="PROGRAMLISTING">
|
---|
6159 | <font color="#000000">Widget Type Quick Description
|
---|
6160 | ===========================================================================
|
---|
6161 | Alphalist Allows a user to select from a list of words, with
|
---|
6162 | the ability to narrow the search list by typing in a
|
---|
6163 | few characters of the desired word.
|
---|
6164 | Buttonbox This creates a multiple button widget.
|
---|
6165 | Calendar Creates a little simple calendar widget.
|
---|
6166 | Dialog Prompts the user with a message, and the user
|
---|
6167 | can pick an answer from the buttons provided.
|
---|
6168 | Entry Allows the user to enter various types of information.
|
---|
6169 | File Selector A file selector built from Cdk base widgets. This
|
---|
6170 | example shows how to create more complicated widgets
|
---|
6171 | using the Cdk widget library.
|
---|
6172 | Graph Draws a graph.
|
---|
6173 | Histogram Draws a histogram.
|
---|
6174 | Item List Creates a pop up field which allows the user to select
|
---|
6175 | one of several choices in a small field. Very useful
|
---|
6176 | for things like days of the week or month names.
|
---|
6177 | Label Displays messages in a pop up box, or the label can be
|
---|
6178 | considered part of the screen.
|
---|
6179 | Marquee Displays a message in a scrolling marquee.
|
---|
6180 | Matrix Creates a complex matrix with lots of options.
|
---|
6181 | Menu Creates a pull-down menu interface.
|
---|
6182 | Multiple Line Entry A multiple line entry field. Very useful
|
---|
6183 | for long fields. (like a description
|
---|
6184 | field)
|
---|
6185 | Radio List Creates a radio button list.
|
---|
6186 | Scale Creates a numeric scale. Used for allowing a user to
|
---|
6187 | pick a numeric value and restrict them to a range of
|
---|
6188 | values.
|
---|
6189 | Scrolling List Creates a scrolling list/menu list.
|
---|
6190 | Scrolling Window Creates a scrolling log file viewer. Can add
|
---|
6191 | information into the window while its running.
|
---|
6192 | A good widget for displaying the progress of
|
---|
6193 | something. (akin to a console window)
|
---|
6194 | Selection List Creates a multiple option selection list.
|
---|
6195 | Slider Akin to the scale widget, this widget provides a
|
---|
6196 | visual slide bar to represent the numeric value.
|
---|
6197 | Template Creates a entry field with character sensitive
|
---|
6198 | positions. Used for pre-formatted fields like
|
---|
6199 | dates and phone numbers.
|
---|
6200 | Viewer This is a file/information viewer. Very useful
|
---|
6201 | when you need to display loads of information.
|
---|
6202 | ===========================================================================</font>
|
---|
6203 | </pre></td>
|
---|
6204 | </tr>
|
---|
6205 | </table>
|
---|
6206 | <p>A few of the widgets are modified by Thomas Dickey in recent
|
---|
6207 | versions.</p>
|
---|
6208 | </div>
|
---|
6209 | <div class="SECT3">
|
---|
6210 | <hr>
|
---|
6211 | <h4 class="SECT3"><a name="CDKATTRACT" id="CDKATTRACT">19.1.2. Some
|
---|
6212 | Attractive Features</a></h4>
|
---|
6213 | <p>Apart from making our life easier with readily usable widgets,
|
---|
6214 | cdk solves one frustrating problem with printing multi colored
|
---|
6215 | strings, justified strings elegantly. Special formatting tags can
|
---|
6216 | be embedded in the strings which are passed to CDK functions. For
|
---|
6217 | Example</p>
|
---|
6218 | <p>If the string</p>
|
---|
6219 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
6220 | <tr>
|
---|
6221 | <td>
|
---|
6222 | <pre class="PROGRAMLISTING">
|
---|
6223 | <font color=
|
---|
6224 | "#000000">"</B/1>This line should have a yellow foreground and a blue
|
---|
6225 | background.<!1>"</font>
|
---|
6226 | </pre></td>
|
---|
6227 | </tr>
|
---|
6228 | </table>
|
---|
6229 | <p>given as a parameter to newCDKLabel(), it prints the line with
|
---|
6230 | yellow foreground and blue background. There are other tags
|
---|
6231 | available for justifying string, embedding special drawing
|
---|
6232 | characters etc.. Please refer to the man page cdk_display(3X) for
|
---|
6233 | details. The man page explains the usage with nice examples.</p>
|
---|
6234 | </div>
|
---|
6235 | <div class="SECT3">
|
---|
6236 | <hr>
|
---|
6237 | <h4 class="SECT3"><a name="CDKCONCLUSION" id=
|
---|
6238 | "CDKCONCLUSION">19.1.3. Conclusion</a></h4>
|
---|
6239 | <p>All in all, CDK is a well-written package of widgets, which if
|
---|
6240 | used properly can form a strong frame work for developing complex
|
---|
6241 | GUI.</p>
|
---|
6242 | </div>
|
---|
6243 | </div>
|
---|
6244 | <div class="SECT2">
|
---|
6245 | <hr>
|
---|
6246 | <h3 class="SECT2"><a name="DIALOG" id="DIALOG">19.2. The
|
---|
6247 | dialog</a></h3>
|
---|
6248 | <p>Long long ago, in September 1994, when few people knew linux,
|
---|
6249 | Jeff Tranter wrote an <a href=
|
---|
6250 | "http://www2.linuxjournal.com/lj-issues/issue5/2807.html" target=
|
---|
6251 | "_top">article</a> on dialog in Linux Journal. He starts the
|
---|
6252 | article with these words..</p>
|
---|
6253 | <p><em>Linux is based on the Unix operating system, but also
|
---|
6254 | features a number of unique and useful kernel features and
|
---|
6255 | application programs that often go beyond what is available under
|
---|
6256 | Unix. One little-known gem is "dialog", a utility for creating
|
---|
6257 | professional-looking dialog boxes from within shell scripts. This
|
---|
6258 | article presents a tutorial introduction to the dialog utility, and
|
---|
6259 | shows examples of how and where it can be used</em></p>
|
---|
6260 | <p>As he explains, dialog is a real gem in making
|
---|
6261 | professional-looking dialog boxes with ease. It creates a variety
|
---|
6262 | of dialog boxes, menus, check lists etc.. It is usually installed
|
---|
6263 | by default. If not, you can download it from <a href=
|
---|
6264 | "http://invisible-island.net/dialog/" target="_top">Thomas
|
---|
6265 | Dickey</a>'s site.</p>
|
---|
6266 | <p>The above-mentioned article gives a very good overview of its
|
---|
6267 | uses and capabilites. The man page has more details. It can be used
|
---|
6268 | in variety of situations. One good example is building of linux
|
---|
6269 | kernel in text mode. Linux kernel uses a modified version of dialog
|
---|
6270 | tailored for its needs.</p>
|
---|
6271 | <p>dialog was initially designed to be used with shell scripts. If
|
---|
6272 | you want to use its functionality in a c program, then you can use
|
---|
6273 | libdialog. The documentation regarding this is sparse. Definitive
|
---|
6274 | reference is the dialog.h header file which comes with the library.
|
---|
6275 | You may need to hack here and there to get the required output. The
|
---|
6276 | source is easily customizable. I have used it on a number of
|
---|
6277 | occasions by modifying the code.</p>
|
---|
6278 | </div>
|
---|
6279 | <div class="SECT2">
|
---|
6280 | <hr>
|
---|
6281 | <h3 class="SECT2"><a name="PERLCURSES" id="PERLCURSES">19.3. Perl
|
---|
6282 | Curses Modules CURSES::FORM and CURSES::WIDGETS</a></h3>
|
---|
6283 | <p>The perl module Curses, Curses::Form and Curses::Widgets give
|
---|
6284 | access to curses from perl. If you have curses and basic perl is
|
---|
6285 | installed, you can get these modules from <a href=
|
---|
6286 | "http://www.cpan.org/modules/01modules.index.html" target=
|
---|
6287 | "_top">CPAN All Modules page</a>. Get the three zipped modules in
|
---|
6288 | the Curses category. Once installed you can use these modules from
|
---|
6289 | perl scripts like any other module. For more information on perl
|
---|
6290 | modules see perlmod man page. The above modules come with good
|
---|
6291 | documentation and they have some demo scripts to test the
|
---|
6292 | functionality. Though the widgets provided are very rudimentary,
|
---|
6293 | these modules provide good access to curses library from perl.</p>
|
---|
6294 | <p>Some of my code examples are converted to perl by Anuradha
|
---|
6295 | Ratnaweera and they are available in the <var class=
|
---|
6296 | "LITERAL">perl</var> directory.</p>
|
---|
6297 | <p>For more information see man pages Curses(3) , Curses::Form(3)
|
---|
6298 | and Curses::Widgets(3). These pages are installed only when the
|
---|
6299 | above modules are acquired and installed.</p>
|
---|
6300 | </div>
|
---|
6301 | </div>
|
---|
6302 | <div class="SECT1">
|
---|
6303 | <hr>
|
---|
6304 | <h2 class="SECT1"><a name="JUSTFORFUN" id="JUSTFORFUN">20. Just For
|
---|
6305 | Fun !!!</a></h2>
|
---|
6306 | <p>This section contains few programs written by me just for fun.
|
---|
6307 | They don't signify a better programming practice or the best way of
|
---|
6308 | using ncurses. They are provided here so as to allow beginners to
|
---|
6309 | get ideas and add more programs to this section. If you have
|
---|
6310 | written a couple of nice, simple programs in curses and want them
|
---|
6311 | to included here, contact <a href="mailto:ppadala@gmail.com"
|
---|
6312 | target="_top">me</a>.</p>
|
---|
6313 | <div class="SECT2">
|
---|
6314 | <hr>
|
---|
6315 | <h3 class="SECT2"><a name="GAMEOFLIFE" id="GAMEOFLIFE">20.1. The
|
---|
6316 | Game of Life</a></h3>
|
---|
6317 | <p>Game of life is a wonder of math. In <a href=
|
---|
6318 | "http://www.math.com/students/wonders/life/life.html" target=
|
---|
6319 | "_top">Paul Callahan</a>'s words</p>
|
---|
6320 | <table border="0" bgcolor="#E0E0E0" width="100%">
|
---|
6321 | <tr>
|
---|
6322 | <td>
|
---|
6323 | <pre class="PROGRAMLISTING">
|
---|
6324 | <font color=
|
---|
6325 | "#000000"><em>The Game of Life (or simply Life) is not a game in the conventional sense. There
|
---|
6326 | are no players, and no winning or losing. Once the "pieces" are placed in the
|
---|
6327 | starting position, the rules determine everything that happens later.
|
---|
6328 | Nevertheless, Life is full of surprises! In most cases, it is impossible to look
|
---|
6329 | at a starting position (or pattern) and see what will happen in the future. The
|
---|
6330 | only way to find out is to follow the rules of the game.</em></font>
|
---|
6331 | </pre></td>
|
---|
6332 | </tr>
|
---|
6333 | </table>
|
---|
6334 | <p>This program starts with a simple inverted U pattern and shows
|
---|
6335 | how wonderful life works. There is a lot of room for improvement in
|
---|
6336 | the program. You can let the user enter pattern of his choice or
|
---|
6337 | even take input from a file. You can also change rules and play
|
---|
6338 | with a lot of variations. Search on <a href="http://www.google.com"
|
---|
6339 | target="_top">google</a> for interesting information on game of
|
---|
6340 | life.</p>
|
---|
6341 | <p><em>File Path: JustForFun/life.c</em></p>
|
---|
6342 | </div>
|
---|
6343 | <div class="SECT2">
|
---|
6344 | <hr>
|
---|
6345 | <h3 class="SECT2"><a name="MAGIC" id="MAGIC">20.2. Magic
|
---|
6346 | Square</a></h3>
|
---|
6347 | <p>Magic Square, another wonder of math, is very simple to
|
---|
6348 | understand but very difficult to make. In a magic square sum of the
|
---|
6349 | numbers in each row, each column is equal. Even diagnol sum can be
|
---|
6350 | equal. There are many variations which have special properties.</p>
|
---|
6351 | <p>This program creates a simple magic square of odd order.</p>
|
---|
6352 | <p><em>File Path: JustForFun/magic.c</em></p>
|
---|
6353 | </div>
|
---|
6354 | <div class="SECT2">
|
---|
6355 | <hr>
|
---|
6356 | <h3 class="SECT2"><a name="HANOI" id="HANOI">20.3. Towers of
|
---|
6357 | Hanoi</a></h3>
|
---|
6358 | <p>The famous towers of hanoi solver. The aim of the game is to
|
---|
6359 | move the disks on the first peg to last peg, using middle peg as a
|
---|
6360 | temporary stay. The catch is not to place a larger disk over a
|
---|
6361 | small disk at any time.</p>
|
---|
6362 | <p><em>File Path: JustForFun/hanoi.c</em></p>
|
---|
6363 | </div>
|
---|
6364 | <div class="SECT2">
|
---|
6365 | <hr>
|
---|
6366 | <h3 class="SECT2"><a name="QUEENS" id="QUEENS">20.4. Queens
|
---|
6367 | Puzzle</a></h3>
|
---|
6368 | <p>The objective of the famous N-Queen puzzle is to put N queens on
|
---|
6369 | a N X N chess board without attacking each other.</p>
|
---|
6370 | <p>This program solves it with a simple backtracking technique.</p>
|
---|
6371 | <p><em>File Path: JustForFun/queens.c</em></p>
|
---|
6372 | </div>
|
---|
6373 | <div class="SECT2">
|
---|
6374 | <hr>
|
---|
6375 | <h3 class="SECT2"><a name="SHUFFLE" id="SHUFFLE">20.5.
|
---|
6376 | Shuffle</a></h3>
|
---|
6377 | <p>A fun game, if you have time to kill.</p>
|
---|
6378 | <p><em>File Path: JustForFun/shuffle.c</em></p>
|
---|
6379 | </div>
|
---|
6380 | <div class="SECT2">
|
---|
6381 | <hr>
|
---|
6382 | <h3 class="SECT2"><a name="TT" id="TT">20.6. Typing Tutor</a></h3>
|
---|
6383 | <p>A simple typing tutor, I created more out of need than for ease
|
---|
6384 | of use. If you know how to put your fingers correctly on the
|
---|
6385 | keyboard, but lack practice, this can be helpful.</p>
|
---|
6386 | <p><em>File Path: JustForFun/tt.c</em></p>
|
---|
6387 | </div>
|
---|
6388 | </div>
|
---|
6389 | <div class="SECT1">
|
---|
6390 | <hr>
|
---|
6391 | <h2 class="SECT1"><a name="REF" id="REF">21. References</a></h2>
|
---|
6392 | <ul>
|
---|
6393 | <li>
|
---|
6394 | <p>NCURSES man pages</p>
|
---|
6395 | </li>
|
---|
6396 | <li>
|
---|
6397 | <p>NCURSES FAQ at <a href=
|
---|
6398 | "http://invisible-island.net/ncurses/ncurses.faq.html" target=
|
---|
6399 | "_top">http://invisible-island.net/ncurses/ncurses.faq.html</a></p>
|
---|
6400 | </li>
|
---|
6401 | <li>
|
---|
6402 | <p>Writing programs with NCURSES by Eric Raymond and Zeyd M.
|
---|
6403 | Ben-Halim at <a href=
|
---|
6404 | "http://invisible-island.net/ncurses/ncurses-intro.html" target=
|
---|
6405 | "_top">http://invisible-island.net/ncurses/ncurses-intro.html</a> -
|
---|
6406 | somewhat obsolete. I was inspired by this document and the
|
---|
6407 | structure of this HOWTO follows from the original document</p>
|
---|
6408 | </li>
|
---|
6409 | </ul>
|
---|
6410 | </div>
|
---|
6411 | </div>
|
---|
6412 | </body>
|
---|
6413 | </html>
|
---|