1 /******************************************************************************
2 *
3 * NSSDC/CDF Windowing widgets.
4 *
5 * Version 1.3b, 13-Nov-97, Hughes STX.
6 *
7 * Modification history:
8 *
9 * V1.0 19-Nov-93, J Love Original version.
10 * V1.0a 22-Feb-94, J Love Spelling lesson.
11 * V1.0b 28-Mar-94, J Love Solaris using GNU C compiler.
12 * V1.1 13-Dec-94, J Love CDF V2.5.
13 * V1.1a 23-Jan-95, J Love Primary/alternate "current" item movement
14 * keys for ItemWindow.
15 * V1.1b 7-Mar-95, J Love Added FieldWindow.
16 * V1.2 11-Apr-95, J Love POSIX/CDFexport.
17 * V1.2a 10-May-95, J Love More CDFexport.
18 * V1.2b 13-Jun-95, J Love catchrX. Linux.
19 * V1.2c 30-Aug-95, J Love CDFexport-related changes. Moved online help
20 * widget to this file. FSI key definitions.
21 * V1.2d 18-Sep-95, J Love Macintosh event handling.
22 * V1.3 26-Aug-96, J Love CDF V2.6.
23 * V1.3a 31-Mar-97, J Love Allowed fields in a FieldWindow to be longer
24 * than their on-screen width.
25 * V1.3b 13-Nov-97, J Love Windows NT/Visual C++.
26 * V1.4 11-Jul-05, M Liu Added MingW port for PC.
27 *
28 ******************************************************************************/
29
30 #include "widgets.h"
31
32 /******************************************************************************
33 * Local macros.
34 ******************************************************************************/
35
36 #define MAX_PCT_LEN 5
37
38 #define DIFF(a,b) BOO((a < b),(b - a),(a - b))
39
40 /******************************************************************************
41 * Local function prototypes.
42 ******************************************************************************/
43
44 static void CalcItemDirections PROTOARGs((
45 int nItems, int NiLines, int *iLineNs, int *iCols, int *iLens,
46 int *iDownTo, int *iUpTo, int *iLeftTo, int *iRightTo
47 ));
48 static void DownArrow PROTOARGs((
49 int *iLineNs, int *iDownTo, int iRowT, int iRowB, Logical iScroll,
50 int *iRowN, int *itemN
51 ));
52 static void UpArrow PROTOARGs((
53 int NiLines, int *iLineNs, int *iUpTo, int iRowT, int iRowB, Logical iScroll,
54 int *iRowN, int *itemN
55 ));
56 static void NextScreen PROTOARGs((
57 int NiRows, int NiLines, int *iLineNs, int *iDownTo, int iRowB, int iRowT,
58 Logical iScroll, int *itemN, int *iRowN
59 ));
60 static void PrevScreen PROTOARGs((
61 int NiRows, int *iLineNs, int *iUpTo, int iRowT, Logical iScroll, int *iRowN,
62 int *itemN
63 ));
64 static void UpdatePctString PROTOARGs((WINDOWid, int, int, int, int, int));
65 static void DrawSection PROTOARGs((
66 WINDOWid, int, int, int, int, char **, int
67 ));
68 static void DrawField PROTOARGs((struct FieldWindowStruct *FW));
69 static void DrawFieldsSection PROTOARGs((struct FieldWindowStruct *FW));
70 static int IWtopRowLineN PROTOARGs((struct ItemWindowStruct *IW));
71 static int FWtopRowLineN PROTOARGs((struct FieldWindowStruct *FW));
72 static void DrawEditSection PROTOARGs((struct EditWindowStruct *EW));
73 static void SetEditCursor PROTOARGs((struct EditWindowStruct *EW));
74
75 /******************************************************************************
76 * ItemWindow.
77 *
78 * Header section.
79 * Items section (scrollable).
80 * Trailer section.
81 *
82 ******************************************************************************/
83
84 #if defined(STDARG)
ItemWindow(int opT,...)85 int ItemWindow (int opT, ...)
86 #else
87 int ItemWindow (va_alist)
88 va_dcl
89 #endif
90 {
91 int op; /* Operation to perform (eg. create new menu,
92 delete menu, etc. */
93 struct ItemWindowStruct *IW; /* Menu configuration. */
94 va_list ap;
95 /***************************************************************************
96 * Start variable-length argument list scanning.
97 ***************************************************************************/
98 #if defined(STDARG)
99 va_start (ap, opT);
100 op = opT;
101 #else
102 VA_START (ap);
103 op = va_arg (ap, int);
104 #endif
105 IW = va_arg (ap, struct ItemWindowStruct *);
106 /***************************************************************************
107 * Perform desired operation. Some operations wait for user input (by
108 * falling through the `switch' statement).
109 ***************************************************************************/
110 switch (op) {
111 /*************************************************************************
112 * Check for new/modified menu.
113 *************************************************************************/
114 case NEWiw:
115 case UPDATEiw: {
116 int nSections; /* Number of sections on window. */
117 int nHorizLines; /* Number of horizontal lines needed. At
118 most 2 horizontal lines will be needed
119 to separate the 3 sections. */
120 int horizRows[2]; /* Rows at which to draw the horizontal
121 lines. */
122 int horizLineN; /* Horizontal line number. */
123 int xRow; /* Used when determining starting rows for
124 the various sections. */
125 Logical highlightItem = FALSE; /* If TRUE, hightlight the
126 current item. */
127 /***********************************************************************
128 * Get remaining arguments.
129 ***********************************************************************/
130 IW->itemN = va_arg (ap, int); /* Initial item number (if any
131 items exist). */
132 va_end (ap);
133 /***********************************************************************
134 * Calculate positions.
135 ***********************************************************************/
136 if (op == NEWiw) {
137 IW->nColS = IW->nColsTotal - 2;
138 nSections = 0;
139 nHorizLines = 0;
140 /********************************************************************\
141 | Start at row 1 (row 0 is top border line).
142 \********************************************************************/
143 xRow = 1;
144 if (IW->NhLines > 0) {
145 nSections++;
146 IW->hRowT = xRow;
147 IW->hRowB = IW->hRowT + IW->NhLines - 1;
148 xRow += IW->NhLines + 1;
149 }
150 if (IW->NiRows > 0) {
151 nSections++;
152 IW->iRowT = xRow;
153 IW->iRowB = IW->iRowT + IW->NiRows - 1;
154 xRow += IW->NiRows + 1;
155 if (nSections > 1) horizRows[nHorizLines++] = IW->iRowT - 1;
156 }
157 else
158 return FALSE; /* An item section must exist. */
159 if (IW->NtLines > 0) {
160 nSections++;
161 IW->tRowT = xRow;
162 IW->tRowB = IW->tRowT + IW->NtLines - 1;
163 xRow += IW->NtLines + 1;
164 if (nSections > 1) horizRows[nHorizLines++] = IW->tRowT - 1;
165 }
166 IW->nRowsTotal = xRow;
167 }
168 /***********************************************************************
169 * Turn off cursor.
170 ***********************************************************************/
171 set_cursor_mode (CURSORoff);
172 /***********************************************************************
173 * Create window?
174 ***********************************************************************/
175 begin_pasteboard_update ();
176 if (op == NEWiw) {
177 create_virtual_display (IW->nRowsTotal, IW->nColsTotal, &(IW->wid),
178 BORDER, NORMAL);
179 paste_virtual_display (IW->wid, IW->ULrow, IW->ULcol);
180 }
181 /***********************************************************************
182 * If specified, write label to window. If this is an update operation,
183 * first overwrite the existing label.
184 ***********************************************************************/
185 if (op == UPDATEiw) draw_horizontal_line (IW->wid, 0, 1, IW->nColS,
186 NORMAL, FALSE);
187 if (IW->label != NULL) {
188 int len = (int) strlen(IW->label);
189 if (len <= IW->nColS) {
190 int nRemainChars = IW->nColS - len;
191 int nCharsBefore = nRemainChars / 2;
192 put_chars (IW->wid, IW->label, len, 0, nCharsBefore + 1, FALSE,
193 REVERSE1);
194 }
195 }
196 /***********************************************************************
197 * If necessary, draw horizontal lines on window.
198 ***********************************************************************/
199 if (op == NEWiw) {
200 for (horizLineN = 0; horizLineN < nHorizLines; horizLineN++) {
201 draw_horizontal_line (IW->wid, horizRows[horizLineN], 0,
202 IW->nColsTotal-1, NORMAL, TRUE);
203 }
204 }
205 /***********************************************************************
206 * If specified, write header section to window. If an update operation,
207 * it is assumed that the number of lines has not changed.
208 ***********************************************************************/
209 if (IW->NhLines > 0) DrawSection (IW->wid, IW->hRowT, IW->hRowB, 0,
210 IW->NhLines, IW->hLines, IW->nColS);
211 /***********************************************************************
212 * Write items section to window and `highlight' current item. The
213 * current item is set to zero initially for a new menu (if items exist,
214 * otherwise it is set to -1). The item section may contain lines but
215 * no items. If an update operation, note that the number of lines may
216 * have changed.
217 ***********************************************************************/
218 if (op == UPDATEiw) {
219 if (IW->iUpTo != NULL) cdf_FreeMemory (IW->iUpTo,
220 FatalError);
221 if (IW->iDownTo != NULL) cdf_FreeMemory (IW->iDownTo,
222 FatalError);
223 if (IW->iLeftTo != NULL) cdf_FreeMemory (IW->iLeftTo,
224 FatalError);
225 if (IW->iRightTo != NULL) cdf_FreeMemory (IW->iRightTo,
226 FatalError);
227 }
228 IW->iUpTo = (int *) cdf_AllocateMemory (IW->nItems * sizeof(int),
229 FatalError);
230 IW->iDownTo = (int *) cdf_AllocateMemory (IW->nItems * sizeof(int),
231 FatalError);
232 IW->iLeftTo = (int *) cdf_AllocateMemory (IW->nItems * sizeof(int),
233 FatalError);
234 IW->iRightTo = (int *) cdf_AllocateMemory (IW->nItems * sizeof(int),
235 FatalError);
236 if (IW->NiLines > 0) {
237 /*******************************************************************
238 * One or more lines in the item section.
239 *******************************************************************/
240 if (IW->nItems > 0) {
241 /*****************************************************************
242 * One or more items in the item section.
243 *****************************************************************/
244 CalcItemDirections (IW->nItems, IW->NiLines, IW->iLineNs,
245 IW->iCols, IW->iLens, IW->iDownTo, IW->iUpTo,
246 IW->iLeftTo, IW->iRightTo);
247 if (IW->NiLines > IW->NiRows)
248 IW->iScroll = TRUE;
249 else
250 IW->iScroll = FALSE;
251 /*******************************************************************
252 * Determine row number for current item. If this is an UPDATEiw
253 * operation, try to keep the row number the same as it was (or as
254 * close as possible).
255 *******************************************************************/
256 if (op == NEWiw)
257 IW->iRowN = MinInt (IW->iRowT +
258 IW->iLineNs[IW->itemN], IW->iRowB);
259 else
260 if (IW->iScroll) {
261 int nLinesFromTop = IW->iLineNs[IW->itemN];
262 int nRowsFromTop = IW->iRowN - IW->iRowT;
263 if (nLinesFromTop < nRowsFromTop)
264 IW->iRowN -= nRowsFromTop - nLinesFromTop;
265 else {
266 int nLinesFromBot = (IW->NiLines-1) - IW->iLineNs[IW->itemN];
267 int nRowsFromBot = IW->iRowB - IW->iRowN;
268 if (nLinesFromBot < nRowsFromBot)
269 IW->iRowN += nRowsFromBot - nLinesFromBot;
270 }
271 }
272 else
273 IW->iRowN = IW->iRowT + IW->iLineNs[IW->itemN];
274 DrawSection (IW->wid, IW->iRowT, IW->iRowB, IWtopRowLineN(IW),
275 IW->NiLines, IW->iLines, IW->nColS);
276 highlightItem = TRUE;
277 }
278 else {
279 /*****************************************************************
280 * No items in the item section (but there are some lines). Just
281 * redraw lines.
282 *****************************************************************/
283 IW->iRowN = IW->iRowT;
284 DrawSection (IW->wid, IW->iRowT, IW->iRowB, IWtopRowLineN(IW),
285 IW->NiLines, IW->iLines, IW->nColS);
286 }
287 }
288 else {
289 /*******************************************************************
290 * No lines in the item section. Erase lines in case there had
291 * previously been lines.
292 *******************************************************************/
293 IW->iRowN = IW->iRowT;
294 erase_display (IW->wid, IW->iRowT, 1, IW->iRowB, IW->nColS);
295 }
296 /*********************************************************************
297 * Setup/display initial percentage indicator.
298 *********************************************************************/
299 if (IW->iPct) {
300 int lineNt = IWtopRowLineN (IW);
301 if (op == NEWiw) {
302 IW->iPctRowN = IW->iRowB + 1;
303 IW->iPctColN = IW->nColsTotal - 7;
304 }
305 UpdatePctString (IW->wid, IW->NiLines, IW->NiRows, lineNt,
306 IW->iPctRowN, IW->iPctColN);
307 }
308 /***********************************************************************
309 * If specified, write trailer section to window. If an update
310 * operation, it is assumed that the number of lines has not changed.
311 ***********************************************************************/
312 if (IW->NtLines > 0) DrawSection (IW->wid, IW->tRowT, IW->tRowB, 0,
313 IW->NtLines, IW->tLines, IW->nColS);
314 /***********************************************************************
315 * Update screen and then highlight the current item (if there is one).
316 * The current item is highlighted after the screen is updated for those
317 * situations where the cursor could not be turned off. Highlighting
318 * the current item last will put the (possible blinking) cursor after
319 * the current item which isn't as distracting as when the cursor is at
320 * the end of the last line of the trailer section.
321 ***********************************************************************/
322 end_pasteboard_update ();
323 if (highlightItem) change_rendition (IW->wid, IW->iRowN,
324 IW->iCols[IW->itemN] + 1, 1,
325 IW->iLens[IW->itemN], REVERSE2);
326 return TRUE;
327 }
328 /*************************************************************************
329 * Check for a beep request.
330 *************************************************************************/
331 case BEEPiw:
332 ring_bell ();
333 va_end (ap);
334 return TRUE;
335 /*************************************************************************
336 * Check if menu should be deleted.
337 *************************************************************************/
338 case DELETEiw:
339 if (IW->iUpTo != NULL) cdf_FreeMemory (IW->iUpTo, FatalError);
340 if (IW->iDownTo != NULL) cdf_FreeMemory (IW->iDownTo, FatalError);
341 if (IW->iLeftTo != NULL) cdf_FreeMemory (IW->iLeftTo, FatalError);
342 if (IW->iRightTo != NULL) cdf_FreeMemory (IW->iRightTo, FatalError);
343 delete_virtual_display (IW->wid);
344 va_end (ap);
345 return TRUE;
346 /*************************************************************************
347 * Check if menu should be erased (but remain in existence).
348 *************************************************************************/
349 case UNDISPLAYiw:
350 unpaste_virtual_display (IW->wid);
351 va_end (ap);
352 return TRUE;
353 /*************************************************************************
354 * Check if menu should be redisplayed (but don't wait for input - a call
355 * with `op = READiw' should be made next).
356 *************************************************************************/
357 case REDISPLAYiw:
358 set_cursor_mode (CURSORoff);
359 paste_virtual_display (IW->wid, IW->ULrow, IW->ULcol);
360 va_end (ap);
361 return TRUE;
362 /*************************************************************************
363 * Get next input. The cursor is positioned and turned off first. The
364 * cursor is positioned for those cases where the cursor cannot be turned
365 * off. A (possibly) blinking cursor at the end of the highlighted item
366 * is less distracting than where it might be.
367 *************************************************************************/
368 case READiw:
369 for (;;) {
370 if (IW->nItems > 0) {
371 set_cursor_abs (IW->wid, IW->iRowN,
372 IW->iCols[IW->itemN] + IW->iLens[IW->itemN] + 1);
373 }
374 set_cursor_mode (CURSORoff);
375 read_input (
376 #if defined(CURSESui)
377 IW->wid,
378 #endif
379 &(IW->key), PASSTHRUri, TRUE);
380 /********************************************************************
381 * Check for an exit key. If no exit keys were specified, any key
382 * causes an exit.
383 ********************************************************************/
384 if (IW->exitChars[0] == NUL) {
385 va_end (ap);
386 return TRUE;
387 }
388 else {
389 int charN;
390 for (charN = 0; IW->exitChars[charN] != NUL; charN++)
391 if (IW->key == IW->exitChars[charN]) {
392 va_end (ap);
393 return TRUE;
394 }
395 }
396 /********************************************************************
397 * Check for next-screen key.
398 ********************************************************************/
399 if (IW->key == IW->NSkey) {
400 begin_pasteboard_update ();
401 if (IW->nItems > 0) {
402 change_rendition (IW->wid, IW->iRowN, IW->iCols[IW->itemN] + 1,
403 1, IW->iLens[IW->itemN], NORMAL);
404 NextScreen (IW->NiRows, IW->NiLines, IW->iLineNs, IW->iDownTo,
405 IW->iRowB, IW->iRowT, IW->iScroll, &(IW->itemN),
406 &(IW->iRowN));
407 DrawSection (IW->wid, IW->iRowT, IW->iRowB, IWtopRowLineN(IW),
408 IW->NiLines, IW->iLines, IW->nColS);
409 if (IW->iPct) UpdatePctString (IW->wid, IW->NiLines, IW->NiRows,
410 IWtopRowLineN(IW), IW->iPctRowN,
411 IW->iPctColN);
412 change_rendition (IW->wid, IW->iRowN, IW->iCols[IW->itemN] + 1,
413 1, IW->iLens[IW->itemN], REVERSE2);
414 }
415 else
416 ring_bell ();
417 end_pasteboard_update ();
418 continue;
419 }
420 /********************************************************************
421 * Check for prev-screen key.
422 ********************************************************************/
423 if (IW->key == IW->PSkey) {
424 begin_pasteboard_update ();
425 if (IW->nItems > 0) {
426 change_rendition (IW->wid, IW->iRowN, IW->iCols[IW->itemN] + 1,
427 1, IW->iLens[IW->itemN], NORMAL);
428 PrevScreen (IW->NiRows, IW->iLineNs, IW->iUpTo, IW->iRowT,
429 IW->iScroll, &(IW->iRowN), &(IW->itemN));
430 DrawSection (IW->wid, IW->iRowT, IW->iRowB, IWtopRowLineN(IW),
431 IW->NiLines, IW->iLines, IW->nColS);
432 if (IW->iPct) UpdatePctString (IW->wid, IW->NiLines, IW->NiRows,
433 IWtopRowLineN(IW), IW->iPctRowN,
434 IW->iPctColN);
435 change_rendition (IW->wid, IW->iRowN, IW->iCols[IW->itemN] + 1,
436 1, IW->iLens[IW->itemN], REVERSE2);
437 }
438 else
439 ring_bell ();
440 end_pasteboard_update ();
441 continue;
442 }
443 /********************************************************************
444 * Check for down arrow key.
445 ********************************************************************/
446 if (IW->key == IW_DOWN || IW->key == IW_DOWNx) {
447 begin_pasteboard_update ();
448 if (IW->nItems > 0) {
449 change_rendition (IW->wid, IW->iRowN, IW->iCols[IW->itemN] + 1,
450 1, IW->iLens[IW->itemN], NORMAL);
451 DownArrow (IW->iLineNs, IW->iDownTo, IW->iRowT, IW->iRowB,
452 IW->iScroll, &(IW->iRowN), &(IW->itemN));
453 DrawSection (IW->wid, IW->iRowT, IW->iRowB, IWtopRowLineN(IW),
454 IW->NiLines, IW->iLines, IW->nColS);
455 if (IW->iPct) UpdatePctString (IW->wid, IW->NiLines, IW->NiRows,
456 IWtopRowLineN(IW), IW->iPctRowN,
457 IW->iPctColN);
458 change_rendition (IW->wid, IW->iRowN, IW->iCols[IW->itemN] + 1,
459 1, IW->iLens[IW->itemN], REVERSE2);
460 }
461 else
462 ring_bell ();
463 end_pasteboard_update ();
464 continue;
465 }
466 /********************************************************************
467 * Check for up arrow key.
468 ********************************************************************/
469 if (IW->key == IW_UP || IW->key == IW_UPx) {
470 begin_pasteboard_update ();
471 if (IW->nItems > 0) {
472 change_rendition (IW->wid, IW->iRowN, IW->iCols[IW->itemN] + 1,
473 1, IW->iLens[IW->itemN], NORMAL);
474 UpArrow (IW->NiLines, IW->iLineNs, IW->iUpTo, IW->iRowT,
475 IW->iRowB, IW->iScroll, &(IW->iRowN), &(IW->itemN));
476 DrawSection (IW->wid, IW->iRowT, IW->iRowB, IWtopRowLineN(IW),
477 IW->NiLines, IW->iLines, IW->nColS);
478 if (IW->iPct) UpdatePctString (IW->wid, IW->NiLines, IW->NiRows,
479 IWtopRowLineN(IW), IW->iPctRowN,
480 IW->iPctColN);
481 change_rendition (IW->wid, IW->iRowN, IW->iCols[IW->itemN] + 1,
482 1, IW->iLens[IW->itemN], REVERSE2);
483 }
484 else
485 ring_bell ();
486 end_pasteboard_update ();
487 continue;
488 }
489 /********************************************************************
490 * Check for left arrow key.
491 ********************************************************************/
492 if (IW->key == IW_LEFT || IW->key == IW_LEFTx) {
493 begin_pasteboard_update ();
494 if (IW->nItems > 0) {
495 change_rendition (IW->wid, IW->iRowN, IW->iCols[IW->itemN] + 1,
496 1, IW->iLens[IW->itemN], NORMAL);
497 IW->itemN = IW->iLeftTo[IW->itemN];
498 change_rendition (IW->wid, IW->iRowN, IW->iCols[IW->itemN] + 1,
499 1, IW->iLens[IW->itemN], REVERSE2);
500 }
501 else
502 ring_bell ();
503 end_pasteboard_update ();
504 continue;
505 }
506 /********************************************************************
507 * Check for right arrow key.
508 ********************************************************************/
509 if (IW->key == IW_RIGHT || IW->key == IW_RIGHTx) {
510 begin_pasteboard_update ();
511 if (IW->nItems > 0) {
512 change_rendition (IW->wid, IW->iRowN, IW->iCols[IW->itemN] + 1,
513 1, IW->iLens[IW->itemN], NORMAL);
514 IW->itemN = IW->iRightTo[IW->itemN];
515 change_rendition (IW->wid, IW->iRowN, IW->iCols[IW->itemN] + 1,
516 1, IW->iLens[IW->itemN], REVERSE2);
517 }
518 else
519 ring_bell ();
520 end_pasteboard_update ();
521 continue;
522 }
523 /********************************************************************
524 * Check for the `refresh' key.
525 ********************************************************************/
526 if (IW->key == IW->refreshChar) {
527 repaint_screen ();
528 continue;
529 }
530 /********************************************************************
531 * Illegal key, ring the bell.
532 ********************************************************************/
533 ring_bell ();
534 }
535 }
536 va_end (ap);
537 return FALSE; /* Illegal operation. */
538 }
539
540 /******************************************************************************
541 * PromptWindow.
542 ******************************************************************************/
543
544 #if defined(STDARG)
PromptWindow(int opT,...)545 int PromptWindow (int opT, ...)
546 #else
547 int PromptWindow (va_alist)
548 va_dcl
549 #endif
550 {
551 int op; /* Operation to perform (eg. create new
552 prompt window, delete window, etc.). */
553 struct PromptWindowStruct *PW;
554 /* Prompt window configuration. */
555 va_list ap;
556 /***************************************************************************
557 * Start variable-length argument list scanning.
558 ***************************************************************************/
559 #if defined(STDARG)
560 va_start (ap, opT);
561 op = opT;
562 #else
563 VA_START (ap);
564 op = va_arg (ap, int);
565 #endif
566 PW = va_arg (ap, struct PromptWindowStruct *);
567 /***************************************************************************
568 * Perform desired operation. Some operations wait for user input (by
569 * falling through the `switch' statement).
570 ***************************************************************************/
571 switch (op) {
572 /*************************************************************************
573 * Check for new menu or menu to be reset.
574 *************************************************************************/
575 case NEWpw:
576 case RESETpw: {
577 /***********************************************************************
578 * Get remaining arguments.
579 ***********************************************************************/
580 PW->curChar = va_arg (ap, int);
581 PW->insertMode = va_arg (ap, Logical);
582 va_end (ap);
583 /***********************************************************************
584 * Calculate positions.
585 ***********************************************************************/
586 if (op == NEWpw) {
587 PW->nColS = PW->nColsTotal - 2;
588 PW->nRowsTotal = (PW->NhLines > 0 ? 1 + PW->NhLines : 0) +
589 3 +
590 (PW->NtLines > 0 ? PW->NtLines + 1 : 0);
591 PW->NvCols = PW->nColsTotal - 6;
592 PW->vRow = (PW->NhLines > 0 ? PW->NhLines + 2 : 1);
593 PW->vLcol = 3;
594 PW->vRcol = PW->vLcol + PW->NvCols - 1;
595 PW->mLcol = 1;
596 PW->mRcol = PW->nColsTotal - 2;
597 if (PW->NhLines > 0) {
598 PW->hRowT = 1;
599 PW->hRowB = PW->hRowT + PW->NhLines - 1;
600 }
601 if (PW->NtLines > 0) {
602 PW->tRowT = (PW->NhLines > 0 ? 1 + PW->NhLines : 0) + 3;
603 PW->tRowB = PW->tRowT + PW->NtLines - 1;
604 }
605 }
606 /***********************************************************************
607 * Create window?
608 ***********************************************************************/
609 begin_pasteboard_update ();
610 if (op == NEWpw) {
611 create_virtual_display (PW->nRowsTotal, PW->nColsTotal, &(PW->wid),
612 BORDER, NORMAL);
613 paste_virtual_display (PW->wid, PW->ULrow, PW->ULcol);
614 }
615 /***********************************************************************
616 * If specified, write label to window.
617 ***********************************************************************/
618 if (PW->label != NULL) {
619 int len = (int) strlen(PW->label);
620 if (len <= PW->nColS) {
621 int nRemainChars = PW->nColS - len;
622 int nCharsBefore = nRemainChars / 2;
623 put_chars (PW->wid, PW->label, len, 0, nCharsBefore + 1, FALSE,
624 REVERSE1);
625 }
626 }
627 /***********************************************************************
628 * Draw necessary horizontal and vertical lines.
629 ***********************************************************************/
630 if (op == NEWpw) {
631 if (PW->NhLines > 0) draw_horizontal_line (PW->wid, PW->vRow-1, 0,
632 PW->nColsTotal-1, NORMAL,
633 TRUE);
634 if (PW->NtLines > 0) draw_horizontal_line (PW->wid, PW->vRow+1, 0,
635 PW->nColsTotal-1, NORMAL,
636 TRUE);
637 draw_vertical_line (PW->wid, PW->vRow - 1, PW->vRow + 1,
638 PW->vLcol - 1, NORMAL, TRUE);
639 draw_vertical_line (PW->wid, PW->vRow - 1, PW->vRow + 1,
640 PW->vRcol + 1, NORMAL, TRUE);
641 }
642 /***********************************************************************
643 * If specified, draw header.
644 ***********************************************************************/
645 if (PW->NhLines > 0) DrawSection (PW->wid, PW->hRowT, PW->hRowB, 0,
646 PW->NhLines, PW->hLines, PW->nColS);
647 /***********************************************************************
648 * Draw initial value (if one exists) and place cursor. If a RESETpw
649 * operation, first erase existing value.
650 ***********************************************************************/
651 if (op == RESETpw) {
652 put_chars (PW->wid, " ", 1, PW->vRow, PW->mLcol, FALSE, NORMAL);
653 erase_display (PW->wid, PW->vRow, PW->vLcol, PW->vRow, PW->vRcol);
654 put_chars (PW->wid, " ", 1, PW->vRow, PW->mRcol, FALSE, NORMAL);
655 }
656 PW->curLen = (int) strlen (PW->value);
657 if (PW->curChar < PW->NvCols) {
658 if (PW->curLen > PW->NvCols) {
659 put_chars (PW->wid, PW->value, PW->NvCols, PW->vRow, PW->vLcol,
660 FALSE, NORMAL);
661 put_chars (PW->wid, ">", 1, PW->vRow, PW->mRcol, FALSE, NORMAL);
662 }
663 else
664 put_chars (PW->wid, PW->value, PW->curLen, PW->vRow, PW->vLcol,
665 FALSE, NORMAL);
666 PW->curCol = PW->vLcol + PW->curChar;
667 }
668 else {
669 put_chars (PW->wid, "<", 1, PW->vRow, PW->mLcol, FALSE, NORMAL);
670 if (PW->curChar < PW->curLen) {
671 put_chars (PW->wid, &(PW->value[PW->curChar - PW->NvCols + 1]),
672 PW->NvCols, PW->vRow, PW->vLcol, FALSE, NORMAL);
673 if (PW->curChar != PW->curLen - 1) put_chars (PW->wid, ">", 1,
674 PW->vRow, PW->mRcol,
675 FALSE, NORMAL);
676 }
677 else
678 put_chars (PW->wid, &(PW->value[PW->curChar - PW->NvCols + 1]),
679 PW->NvCols - 1, PW->vRow, PW->vLcol, FALSE, NORMAL);
680 PW->curCol = PW->vRcol;
681 }
682 /***********************************************************************
683 * If specified, draw trailer.
684 ***********************************************************************/
685 if (PW->NtLines > 0) DrawSection (PW->wid, PW->tRowT, PW->tRowB, 0,
686 PW->NtLines, PW->tLines, PW->nColS);
687 /***********************************************************************
688 * Update screen.
689 ***********************************************************************/
690 end_pasteboard_update ();
691 /***********************************************************************
692 * Position cursor (which must occur after the pasteboard batching is
693 * ended).
694 ***********************************************************************/
695 set_cursor_abs (PW->wid, PW->vRow, PW->curCol);
696 set_cursor_mode (CURSORon);
697 return TRUE;
698 }
699 /*************************************************************************
700 * Check for a beep request.
701 *************************************************************************/
702 case BEEPpw:
703 ring_bell ();
704 va_end (ap);
705 return TRUE;
706 /*************************************************************************
707 * Check if window should be erased (but remain in existence).
708 *************************************************************************/
709 case UNDISPLAYpw:
710 unpaste_virtual_display (PW->wid);
711 va_end (ap);
712 return TRUE;
713 /*************************************************************************
714 * Check if window should be redisplayed (don't wait for input - a call
715 * with `op = READpw' should be made next).
716 *************************************************************************/
717 case REDISPLAYpw:
718 paste_virtual_display (PW->wid, PW->ULrow, PW->ULcol);
719 set_cursor_abs (PW->wid, PW->vRow, PW->curCol);
720 set_cursor_mode (CURSORon);
721 va_end (ap);
722 return TRUE;
723 /*************************************************************************
724 * Check if window should be deleted.
725 *************************************************************************/
726 case DELETEpw:
727 delete_virtual_display (PW->wid);
728 va_end (ap);
729 return TRUE;
730 /*************************************************************************
731 * Read keystrokes until `exit' key entered.
732 *************************************************************************/
733 case READpw: {
734 int colsToEnd; /* Number of columns from cursor to the right-
735 most column of the value field (including
736 the cursor position). */
737 int offRight; /* Number of characters to the right of the
738 last column in the value field (the right
739 `more' indicator should be ON). This can
740 be zero or negative. */
741 int offLeft; /* Number of characters to the left of the
742 first column in the value field (the left
743 `more' indicator should be ON). This can
744 be zero or negative. */
745 int charsToEnd; /* Number of characters from the cursor to the
746 end of the value (including at the cursor
747 position). */
748 int leftColChar; /* Character number at left column of value
749 field. */
750 int rightColChar; /* Character number at right column of value
751 field. */
752 int charN; /* Character number. */
753 /***********************************************************************
754 * Set cursor mode/position.
755 ***********************************************************************/
756 set_cursor_abs (PW->wid, PW->vRow, PW->curCol);
757 set_cursor_mode (CURSORon);
758 /***********************************************************************
759 * Read/process keys until an `exit' key...
760 ***********************************************************************/
761 for (;;) {
762 read_input (
763 #if defined(CURSESui)
764 PW->wid,
765 #endif
766 &(PW->key), PASSTHRUri, TRUE);
767 /********************************************************************
768 * Check for an `exit' key.
769 ********************************************************************/
770 for (charN = 0; PW->exitChars[charN] != NUL; charN++) {
771 if (PW->key == PW->exitChars[charN]) {
772 va_end (ap);
773 return TRUE;
774 }
775 }
776 /********************************************************************
777 * Check for left arrow.
778 ********************************************************************/
779 if (PW->key == KB_LEFTARROW) {
780 begin_pasteboard_update ();
781 if (PW->curCol > PW->vLcol) {
782 PW->curChar--;
783 PW->curCol--;
784 }
785 else
786 if (PW->curChar > 0) {
787 PW->curChar--;
788 charsToEnd = PW->curLen - PW->curChar;
789 put_chars (PW->wid, &(PW->value[PW->curChar]),
790 MINIMUM(charsToEnd,PW->NvCols), PW->vRow, PW->vLcol,
791 FALSE, NORMAL);
792 if (PW->curChar == 0) put_chars (PW->wid, " ", 1, PW->vRow,
793 PW->mLcol, FALSE, NORMAL);
794 offRight = charsToEnd - PW->NvCols;
795 if (offRight == 1) put_chars (PW->wid, ">", 1, PW->vRow,
796 PW->mRcol, FALSE, NORMAL);
797 }
798 else
799 ring_bell ();
800 end_pasteboard_update ();
801 set_cursor_abs (PW->wid, PW->vRow, PW->curCol);
802 continue;
803 }
804 /********************************************************************
805 * Check for right arrow.
806 ********************************************************************/
807 if (PW->key == KB_RIGHTARROW) {
808 begin_pasteboard_update ();
809 if (PW->curCol < PW->vRcol) {
810 if (PW->curChar < PW->curLen) {
811 PW->curChar++;
812 PW->curCol++;
813 }
814 else
815 ring_bell ();
816 }
817 else
818 if (PW->curChar < PW->curLen) {
819 PW->curChar++;
820 leftColChar = PW->curChar - PW->NvCols + 1;
821 if (PW->curChar == PW->curLen) {
822 put_chars (PW->wid, &(PW->value[leftColChar]),
823 PW->NvCols - 1, PW->vRow, PW->vLcol, FALSE,
824 NORMAL);
825 put_chars (PW->wid, " ", 1, PW->vRow, PW->vRcol, FALSE,
826 NORMAL);
827 }
828 else
829 put_chars (PW->wid, &(PW->value[leftColChar]), PW->NvCols,
830 PW->vRow, PW->vLcol, FALSE, NORMAL);
831 put_chars (PW->wid, "<", 1, PW->vRow, PW->mLcol, FALSE,
832 NORMAL);
833 charsToEnd = PW->curLen - PW->curChar;
834 colsToEnd = PW->vRcol - PW->curCol + 1;
835 offRight = charsToEnd - colsToEnd;
836 if (offRight == 0) put_chars (PW->wid, " ", 1, PW->vRow,
837 PW->mRcol, FALSE, NORMAL);
838 }
839 else
840 ring_bell ();
841 end_pasteboard_update ();
842 set_cursor_abs (PW->wid, PW->vRow, PW->curCol);
843 continue;
844 }
845 /********************************************************************
846 * Check for delete key.
847 ********************************************************************/
848 if (PW->key == KB_DELETE) {
849 begin_pasteboard_update ();
850 if (PW->curCol == PW->vLcol) {
851 if (PW->curChar > 0) {
852 charsToEnd = PW->curLen - PW->curChar;
853 memmove (&PW->value[PW->curChar-1], &PW->value[PW->curChar],
854 charsToEnd + 1);
855 PW->curChar--;
856 PW->curLen--;
857 if (PW->curChar == 0) put_chars (PW->wid, " ", 1, PW->vRow,
858 PW->mLcol, FALSE, NORMAL);
859 }
860 else
861 ring_bell ();
862 }
863 else {
864 charsToEnd = PW->curLen - PW->curChar;
865 colsToEnd = PW->vRcol - PW->curCol + 1;
866 offRight = charsToEnd - colsToEnd;
867 if (offRight > 0) {
868 memmove (&(PW->value[PW->curChar-1]),
869 &(PW->value[PW->curChar]), charsToEnd + 1);
870 PW->curChar--;
871 PW->curCol--;
872 PW->curLen--;
873 colsToEnd++;
874 put_chars (PW->wid, &(PW->value[PW->curChar]), colsToEnd,
875 PW->vRow, PW->curCol, FALSE, NORMAL);
876 offRight--;
877 if (offRight == 0) put_chars (PW->wid, " ", 1, PW->vRow,
878 PW->mRcol, FALSE, NORMAL);
879 }
880 else
881 if (charsToEnd > 0) {
882 memmove (&(PW->value[PW->curChar-1]),
883 &(PW->value[PW->curChar]), charsToEnd + 1);
884 PW->curChar--;
885 PW->curCol--;
886 PW->curLen--;
887 put_chars (PW->wid, &(PW->value[PW->curChar]), charsToEnd,
888 PW->vRow, PW->curCol, FALSE, NORMAL);
889 put_chars (PW->wid, " ", 1, PW->vRow,
890 PW->curCol + charsToEnd, FALSE, NORMAL);
891 }
892 else {
893 PW->curChar--;
894 PW->value[PW->curChar] = NUL;
895 PW->curLen--;
896 PW->curCol--;
897 put_chars (PW->wid, " ", 1, PW->vRow, PW->curCol, FALSE,
898 NORMAL);
899 }
900 }
901 end_pasteboard_update ();
902 set_cursor_abs (PW->wid, PW->vRow, PW->curCol);
903 continue;
904 }
905 /********************************************************************
906 * Check for the `refresh' key.
907 ********************************************************************/
908 if (PW->key == PW->refreshChar) {
909 repaint_screen ();
910 continue;
911 }
912 /********************************************************************
913 * Check for the SOL key. If the current length of the value is
914 * greater than the number of available columns, the right `more'
915 * indicator is drawn (even though it may already be drawn).
916 ********************************************************************/
917 if (PW->key == PW->SOLchar) {
918 begin_pasteboard_update ();
919 leftColChar = PW->curChar - (PW->curCol - PW->vLcol);
920 if (leftColChar > 0) {
921 put_chars (PW->wid, " ", 1, PW->vRow, PW->mLcol, FALSE, NORMAL);
922 put_chars (PW->wid, PW->value, PW->NvCols, PW->vRow, PW->vLcol,
923 FALSE, NORMAL);
924 if (PW->curLen > PW->NvCols) put_chars (PW->wid, ">", 1,
925 PW->vRow, PW->mRcol,
926 FALSE, NORMAL);
927 }
928 PW->curCol = PW->vLcol;
929 PW->curChar = 0;
930 end_pasteboard_update ();
931 set_cursor_abs (PW->wid, PW->vRow, PW->curCol);
932 continue;
933 }
934 /********************************************************************
935 * Check for the EOL key. The `right column character' is used to
936 * determine if moving the cursor to the end of the value will cause
937 * characters to be off the left end of the value field. The left
938 * and right `more' indicators are updated regardless of how they may
939 * have already been.
940 ********************************************************************/
941 if (PW->key == PW->EOLchar) {
942 begin_pasteboard_update ();
943 rightColChar = PW->curChar + (PW->vRcol - PW->curCol);
944 if (rightColChar < PW->curLen) {
945 put_chars (PW->wid, "<", 1, PW->vRow, PW->mLcol, FALSE, NORMAL);
946 put_chars (PW->wid, &(PW->value[PW->curLen - PW->NvCols + 1]),
947 PW->NvCols - 1, PW->vRow, PW->vLcol, FALSE, NORMAL);
948 put_chars (PW->wid, " ", 1, PW->vRow, PW->vRcol, FALSE, NORMAL);
949 put_chars (PW->wid, " ", 1, PW->vRow, PW->mRcol, FALSE, NORMAL);
950 }
951 PW->curCol = MinInt (PW->vLcol + PW->curLen, PW->vRcol);
952 PW->curChar = PW->curLen;
953 end_pasteboard_update ();
954 set_cursor_abs (PW->wid, PW->vRow, PW->curCol);
955 continue;
956 }
957 /********************************************************************
958 * Check for the toggle insert/overstrike mode key.
959 ********************************************************************/
960 if (PW->key == PW->TOGGLEchar) {
961 PW->insertMode = (PW->insertMode ? FALSE : TRUE);
962 continue;
963 }
964 /********************************************************************
965 * Check for a printable character to insert/overstrike.
966 ********************************************************************/
967 if (Printable(PW->key)) {
968 begin_pasteboard_update ();
969 charsToEnd = PW->curLen - PW->curChar;
970 colsToEnd = PW->vRcol - PW->curCol + 1;
971 if (charsToEnd == 0) {
972 /****************************************************************
973 * The cursor is at the end of the value.
974 ****************************************************************/
975 if (PW->curLen < PW->maxChars) {
976 catchrX (PW->value, PW->key, PW->maxChars);
977 PW->curLen++;
978 PW->curChar++;
979 if (colsToEnd > 1) {
980 put_chars (PW->wid, &(PW->value[PW->curChar-1]), 1, PW->vRow,
981 PW->curCol, FALSE, NORMAL);
982 PW->curCol++;
983 }
984 else {
985 leftColChar = PW->curChar - PW->NvCols + 1;
986 put_chars (PW->wid, &(PW->value[leftColChar]), PW->NvCols-1,
987 PW->vRow, PW->vLcol, FALSE, NORMAL);
988 offLeft = PW->curLen - PW->NvCols + 1;
989 if (offLeft == 1) put_chars (PW->wid, "<", 1, PW->vRow,
990 PW->mLcol, FALSE, NORMAL);
991 }
992 }
993 else
994 ring_bell ();
995 }
996 else {
997 /****************************************************************
998 * The cursor is somewhere in the middle of the value.
999 ****************************************************************/
1000 if (!PW->insertMode ||
1001 (PW->insertMode && PW->curLen < PW->maxChars)) {
1002 if (PW->insertMode) {
1003 /************************************************************
1004 * Insert mode.
1005 ************************************************************/
1006 memmove (&(PW->value[PW->curChar+1]),
1007 &(PW->value[PW->curChar]), charsToEnd + 1);
1008 PW->value[PW->curChar] = PW->key;
1009 PW->curLen++;
1010 if (colsToEnd > 1) {
1011 /**********************************************************
1012 * The cursor is not in the last column of the value field.
1013 **********************************************************/
1014 put_chars (PW->wid, &(PW->value[PW->curChar]),
1015 MINIMUM(colsToEnd,charsToEnd + 1),
1016 PW->vRow, PW->curCol, FALSE, NORMAL);
1017 PW->curChar++;
1018 PW->curCol++;
1019 charsToEnd = PW->curLen - PW->curChar;
1020 colsToEnd = PW->vRcol - PW->curCol + 1;
1021 offRight = charsToEnd - colsToEnd;
1022 if (offRight == 1) put_chars (PW->wid, ">", 1, PW->vRow,
1023 PW->mRcol, FALSE, NORMAL);
1024 }
1025 else {
1026 /**********************************************************
1027 * The cursor is in the last column of the value field.
1028 **********************************************************/
1029 PW->curChar++;
1030 leftColChar = PW->curChar - PW->NvCols + 1;
1031 put_chars (PW->wid, &(PW->value[leftColChar]), PW->NvCols,
1032 PW->vRow, PW->vLcol, FALSE, NORMAL);
1033 if (leftColChar == 1) put_chars (PW->wid, "<", 1, PW->vRow,
1034 PW->mLcol, FALSE, NORMAL);
1035 }
1036 }
1037 else {
1038 /************************************************************
1039 * Overstrike mode.
1040 ************************************************************/
1041 PW->value[PW->curChar] = PW->key;
1042 if (colsToEnd > 1) {
1043 /**********************************************************
1044 * The cursor is not in the last column of the value field.
1045 **********************************************************/
1046 put_chars (PW->wid, &(PW->value[PW->curChar]), 1, PW->vRow,
1047 PW->curCol, FALSE, NORMAL);
1048 PW->curChar++;
1049 PW->curCol++;
1050 }
1051 else {
1052 /**********************************************************
1053 * The cursor is in the last column of the value field.
1054 **********************************************************/
1055 offRight = charsToEnd - 1;
1056 if (offRight > 0) {
1057 /********************************************************
1058 * One or more character off the right end.
1059 ********************************************************/
1060 PW->curChar++;
1061 leftColChar = PW->curChar - PW->NvCols + 1;
1062 put_chars (PW->wid, &(PW->value[leftColChar]),
1063 PW->NvCols, PW->vRow, PW->vLcol, FALSE,
1064 NORMAL);
1065 if (leftColChar == 1) put_chars (PW->wid, "<", 1,
1066 PW->vRow, PW->mLcol,
1067 FALSE, NORMAL);
1068 offRight--;
1069 if (offRight == 0) put_chars (PW->wid, " ", 1, PW->vRow,
1070 PW->mRcol, FALSE, NORMAL);
1071 }
1072 else {
1073 /********************************************************
1074 * Cursor is on the last character.
1075 ********************************************************/
1076 PW->curChar++;
1077 leftColChar = PW->curChar - PW->NvCols + 1;
1078 put_chars (PW->wid, &(PW->value[leftColChar]),
1079 PW->NvCols - 1, PW->vRow, PW->vLcol, FALSE,
1080 NORMAL);
1081 put_chars (PW->wid, " ", 1, PW->vRow, PW->vRcol, FALSE,
1082 NORMAL);
1083 if (leftColChar == 1) put_chars (PW->wid, "<", 1,
1084 PW->vRow, PW->mLcol,
1085 FALSE, NORMAL);
1086 }
1087 }
1088 }
1089 }
1090 else
1091 ring_bell ();
1092 }
1093 end_pasteboard_update ();
1094 set_cursor_abs (PW->wid, PW->vRow, PW->curCol);
1095 continue;
1096 }
1097 /********************************************************************
1098 * None of the above, illegal character.
1099 ********************************************************************/
1100 ring_bell ();
1101 }
1102 }
1103 }
1104 va_end (ap);
1105 return FALSE; /* Illegal operation. */
1106 }
1107
1108 /******************************************************************************
1109 * EditWindow.
1110 ******************************************************************************/
1111
1112 #if defined(STDARG)
EditWindow(int opT,...)1113 int EditWindow (int opT, ...)
1114 #else
1115 int EditWindow (va_alist)
1116 va_dcl
1117 #endif
1118 {
1119 int op; /* Operation to perform (eg. create new
1120 edit window, delete window, etc.). */
1121 struct EditWindowStruct *EW; /* Edit window configuration. */
1122 va_list ap;
1123 /***************************************************************************
1124 * Start variable-length argument list scanning.
1125 ***************************************************************************/
1126 #if defined(STDARG)
1127 va_start (ap, opT);
1128 op = opT;
1129 #else
1130 VA_START (ap);
1131 op = va_arg (ap, int);
1132 #endif
1133 EW = va_arg (ap, struct EditWindowStruct *);
1134 /***************************************************************************
1135 * Perform desired operation. Some operations wait for user input (by
1136 * falling through the `switch' statement).
1137 ***************************************************************************/
1138 switch (op) {
1139 /*************************************************************************
1140 * Check for new menu.
1141 *************************************************************************/
1142 case NEWew:
1143 case UPDATEew: {
1144 /***********************************************************************
1145 * Get remaining arguments.
1146 ***********************************************************************/
1147 EW->insertMode = va_arg (ap, Logical);
1148 va_end (ap);
1149 /***********************************************************************
1150 * Create window?
1151 ***********************************************************************/
1152 begin_pasteboard_update ();
1153 if (op == NEWew) {
1154 EW->nRowsTotal = BOO(EW->NhLines > 0,1,0) + EW->NhLines +
1155 BOO(EW->NeRows > 0,1,0) + EW->NeRows +
1156 BOO(EW->NtLines > 0,1,0) + EW->NtLines + 1;
1157 create_virtual_display (EW->nRowsTotal, EW->nColsTotal, &(EW->wid),
1158 BORDER, NORMAL);
1159 paste_virtual_display (EW->wid, EW->ULrow, EW->ULcol);
1160 EW->nColS = EW->nColsTotal - 2;
1161 }
1162 /***********************************************************************
1163 * If specified, write label to window. If this is an update operation,
1164 * first overwrite the existing label.
1165 ***********************************************************************/
1166 if (op == UPDATEew) draw_horizontal_line (EW->wid, 0, 1, EW->nColS,
1167 NORMAL, FALSE);
1168 if (EW->label != NULL) {
1169 int len = (int) strlen(EW->label);
1170 if (len <= EW->nColS) {
1171 int nRemainChars = EW->nColS - len;
1172 int nCharsBefore = nRemainChars / 2;
1173 put_chars (EW->wid, EW->label, len, 0, nCharsBefore + 1, FALSE,
1174 REVERSE1);
1175 }
1176 }
1177 /***********************************************************************
1178 * If necessary, calculate positions and draw horizontal lines on window.
1179 ***********************************************************************/
1180 if (op == NEWew) {
1181 int nSections = 0; /* Number of sections in the window. */
1182 int xRow = 1; /* Start at row 1 (row 0 is top border line). */
1183 if (EW->NhLines > 0) {
1184 nSections++;
1185 EW->hRowT = xRow;
1186 EW->hRowB = EW->hRowT + EW->NhLines - 1;
1187 xRow += EW->NhLines + 1;
1188 }
1189 if (EW->NeRows > 0) {
1190 nSections++;
1191 EW->eRowT = xRow;
1192 EW->eRowB = EW->eRowT + EW->NeRows - 1;
1193 xRow += EW->NeRows + 1;
1194 if (nSections > 1) draw_horizontal_line (EW->wid, EW->eRowT - 1, 0,
1195 EW->nColsTotal - 1, NORMAL,
1196 TRUE);
1197 }
1198 if (EW->NtLines > 0) {
1199 nSections++;
1200 EW->tRowT = xRow;
1201 EW->tRowB = EW->tRowT + EW->NtLines - 1;
1202 xRow += EW->NtLines + 1;
1203 if (nSections > 1) draw_horizontal_line (EW->wid, EW->tRowT - 1, 0,
1204 EW->nColsTotal - 1, NORMAL,
1205 TRUE);
1206 }
1207 }
1208 /***********************************************************************
1209 * If specified, write header section to window. If an update operation,
1210 * it is assumed that the number of lines has not changed.
1211 ***********************************************************************/
1212 if (EW->NhLines > 0) DrawSection (EW->wid, EW->hRowT, EW->hRowB, 0,
1213 EW->NhLines, EW->hLines, EW->nColS);
1214 /***********************************************************************
1215 * Write edit section to window. If an update operation, note that the
1216 * text may have changed (to more or less lines) but not the number of
1217 * rows.
1218 ***********************************************************************/
1219 EW->nChars = (int) strlen(EW->eText);
1220 EW->xChars = EW->nChars;
1221 EW->cursorRow = EW->eRowT;
1222 EW->cursorCol = 1;
1223 EW->firstChar = 0;
1224 EW->cursorChar = 0;
1225 DrawEditSection (EW);
1226 /*********************************************************************
1227 * Setup/display initial percentage indicator.
1228 *********************************************************************/
1229 if (EW->ePct) {
1230 if (op == NEWew) {
1231 EW->ePctRowN = EW->eRowB + 1;
1232 EW->ePctColN = EW->nColsTotal - 7;
1233 }
1234 UpdatePctString (EW->wid, EW->nChars + 1, 1, EW->cursorChar,
1235 EW->ePctRowN, EW->ePctColN);
1236 }
1237 /***********************************************************************
1238 * If specified, write trailer section to window. If an update
1239 * operation, it is assumed that the number of lines has not changed.
1240 ***********************************************************************/
1241 if (EW->NtLines > 0) DrawSection (EW->wid, EW->tRowT, EW->tRowB, 0,
1242 EW->NtLines, EW->tLines, EW->nColS);
1243 /***********************************************************************
1244 * Update screen.
1245 ***********************************************************************/
1246 end_pasteboard_update ();
1247 /***********************************************************************
1248 * Position cursor (which must occur after the pasteboard batching is
1249 * ended).
1250 ***********************************************************************/
1251 set_cursor_abs (EW->wid, EW->cursorRow, EW->cursorCol);
1252 set_cursor_mode (CURSORon);
1253 return TRUE;
1254 }
1255 /*************************************************************************
1256 * Check for a beep request.
1257 *************************************************************************/
1258 case BEEPew:
1259 ring_bell ();
1260 va_end (ap);
1261 return TRUE;
1262 /*************************************************************************
1263 * Check if menu should be deleted.
1264 *************************************************************************/
1265 case DELETEew:
1266 delete_virtual_display (EW->wid);
1267 va_end (ap);
1268 return TRUE;
1269 /*************************************************************************
1270 * Get next input (exit key).
1271 *************************************************************************/
1272 case READew: {
1273 int length, i, count;
1274 set_cursor_abs (EW->wid, EW->cursorRow, EW->cursorCol);
1275 set_cursor_mode (CURSORon);
1276 for (;;) {
1277 read_input (
1278 #if defined(CURSESui)
1279 EW->wid,
1280 #endif
1281 &(EW->key), PASSTHRUri, TRUE);
1282 /********************************************************************
1283 * Check for an exit key. If no exit keys were specified, any key
1284 * causes an exit.
1285 ********************************************************************/
1286 if (EW->exitChars[0] == NUL) {
1287 va_end (ap);
1288 return TRUE;
1289 }
1290 else {
1291 int charN;
1292 for (charN = 0; EW->exitChars[charN] != NUL; charN++) {
1293 if (EW->key == EW->exitChars[charN]) {
1294 va_end (ap);
1295 return TRUE;
1296 }
1297 }
1298 }
1299 /********************************************************************
1300 * Check for start-of-line key.
1301 ********************************************************************/
1302 if (EW->key == EW->SOLkey) {
1303 ring_bell ();
1304 continue;
1305 }
1306 /********************************************************************
1307 * Check for end-of-line key.
1308 ********************************************************************/
1309 if (EW->key == EW->EOLkey) {
1310 ring_bell ();
1311 continue;
1312 }
1313 /********************************************************************
1314 * Check for start-of-text key.
1315 ********************************************************************/
1316 if (EW->key == EW->SOTkey) {
1317 ring_bell ();
1318 continue;
1319 }
1320 /********************************************************************
1321 * Check for end-of-text key.
1322 ********************************************************************/
1323 if (EW->key == EW->EOTkey) {
1324 ring_bell ();
1325 continue;
1326 }
1327 /********************************************************************
1328 * Check for next-word key.
1329 ********************************************************************/
1330 if (EW->key == EW->NWkey) {
1331 ring_bell ();
1332 continue;
1333 }
1334 /********************************************************************
1335 * Check for delete-line key.
1336 ********************************************************************/
1337 if (EW->key == EW->DLkey) {
1338 if (EW->readOnly)
1339 ring_bell ();
1340 else {
1341 ring_bell ();
1342 }
1343 continue;
1344 }
1345 /********************************************************************
1346 * Check for next-screen key.
1347 ********************************************************************/
1348 if (EW->key == EW->NSkey) {
1349 if (EW->eText[EW->cursorChar] == NUL)
1350 ring_bell ();
1351 else {
1352 int count; /* Number of lines that cursor is moved down. */
1353 /****************************************************************
1354 * Move the cursor to the beginning of the line.
1355 ****************************************************************/
1356 while (EW->cursorChar > 0) {
1357 if (EW->eText[EW->cursorChar-1] == Nl) break;
1358 EW->cursorChar--;
1359 }
1360 /****************************************************************
1361 * Move the cursor down the number of rows displayed (or less).
1362 ****************************************************************/
1363 for (count = 0;
1364 EW->eText[EW->cursorChar] != NUL;
1365 EW->cursorChar++) {
1366 if (EW->eText[EW->cursorChar] == Nl) {
1367 count++;
1368 if (count == EW->NeRows) {
1369 EW->cursorChar++;
1370 break;
1371 }
1372 }
1373 }
1374 /****************************************************************
1375 * Move the `first character displayed' down the same number of
1376 * rows (if necessary).
1377 ****************************************************************/
1378 if (EW->cursorRow + count > EW->eRowB) {
1379 int count1; /* Number of lines after the first displayed. */
1380 int charN;
1381 for (count1 = 0, charN = EW->firstChar;
1382 EW->eText[charN] != NUL; charN++) {
1383 if (EW->eText[charN] == Nl) count1++;
1384 }
1385 count1 -= (EW->NeRows - 1);
1386 count1 = MINIMUM(count1,count);
1387 while (count1 > 0) {
1388 if (EW->eText[EW->firstChar] == Nl) count1--;
1389 EW->firstChar++;
1390 }
1391 DrawEditSection (EW);
1392 }
1393 /****************************************************************
1394 * Update the percentage and cursor position.
1395 ****************************************************************/
1396 if (EW->ePct) UpdatePctString (EW->wid, EW->nChars + 1, 1,
1397 EW->cursorChar, EW->ePctRowN,
1398 EW->ePctColN);
1399 SetEditCursor (EW);
1400 }
1401 continue;
1402 }
1403 /********************************************************************
1404 * Check for prev-screen key.
1405 ********************************************************************/
1406 if (EW->key == EW->PSkey) {
1407 if (EW->cursorChar == 0)
1408 ring_bell ();
1409 else {
1410 int count; /* Number of lines that cursor is moved up. */
1411 /****************************************************************
1412 * Move the cursor to the beginning of the line.
1413 ****************************************************************/
1414 while (EW->cursorChar > 0) {
1415 if (EW->eText[EW->cursorChar-1] == Nl) break;
1416 EW->cursorChar--;
1417 }
1418 /****************************************************************
1419 * Move the cursor up the number of rows displayed (or less).
1420 ****************************************************************/
1421 for (count = 0; EW->cursorChar > 0; EW->cursorChar--) {
1422 if (EW->eText[EW->cursorChar] == Nl) {
1423 count++;
1424 if (count == EW->NeRows) {
1425 if (EW->cursorChar > 0) {
1426 EW->cursorChar--;
1427 while (EW->cursorChar > 0) {
1428 if (EW->eText[EW->cursorChar-1] == Nl) break;
1429 EW->cursorChar--;
1430 }
1431 }
1432 break;
1433 }
1434 }
1435 }
1436 /****************************************************************
1437 * Move the `first character displayed' up the same number of
1438 * rows (if necessary).
1439 ****************************************************************/
1440 if (EW->cursorRow - count < EW->eRowT) {
1441 while (EW->firstChar > 0) {
1442 if (EW->eText[EW->firstChar] == Nl) {
1443 count--;
1444 if (count == 0) {
1445 if (EW->firstChar > 0) {
1446 EW->firstChar--;
1447 while (EW->firstChar > 0) {
1448 if (EW->eText[EW->firstChar-1] == Nl) break;
1449 EW->firstChar--;
1450 }
1451 }
1452 break;
1453 }
1454 }
1455 EW->firstChar--;
1456 }
1457 DrawEditSection (EW);
1458 }
1459 /****************************************************************
1460 * Update the percentage and cursor position.
1461 ****************************************************************/
1462 if (EW->ePct) UpdatePctString (EW->wid, EW->nChars + 1, 1,
1463 EW->cursorChar, EW->ePctRowN,
1464 EW->ePctColN);
1465 SetEditCursor (EW);
1466 }
1467 continue;
1468 }
1469 /********************************************************************
1470 * Check for down arrow key.
1471 ********************************************************************/
1472 if (EW->key == KB_DOWNARROW) {
1473 char *nextNL = strchr (&(EW->eText[EW->cursorChar]), Nl);
1474 if (nextNL == NULL)
1475 ring_bell ();
1476 else {
1477 int toNL = (int) (nextNL - &(EW->eText[EW->cursorChar]));
1478 EW->cursorChar += (toNL + 1);
1479 for (i = 1; i < EW->cursorCol; i++) {
1480 if (EW->eText[EW->cursorChar] == Nl) break;
1481 if (EW->eText[EW->cursorChar] == NUL) break;
1482 EW->cursorChar++;
1483 }
1484 if (EW->cursorRow == EW->eRowB) {
1485 while (EW->eText[EW->firstChar] != Nl) EW->firstChar++;
1486 EW->firstChar++;
1487 DrawEditSection (EW);
1488 }
1489 if (EW->ePct) UpdatePctString (EW->wid, EW->nChars + 1, 1,
1490 EW->cursorChar, EW->ePctRowN,
1491 EW->ePctColN);
1492 SetEditCursor (EW);
1493 }
1494 continue;
1495 }
1496 /********************************************************************
1497 * Check for up arrow key.
1498 ********************************************************************/
1499 if (EW->key == KB_UPARROW) {
1500 if (EW->firstChar == 0 && EW->cursorRow == EW->eRowT)
1501 ring_bell ();
1502 else {
1503 /****************************************************************
1504 * If the cursor is on the top line then scroll up one line.
1505 ****************************************************************/
1506 if (EW->cursorRow == EW->eRowT) {
1507 for (EW->firstChar--; EW->firstChar > 0; EW->firstChar--) {
1508 if (EW->eText[EW->firstChar-1] == Nl) break;
1509 }
1510 DrawEditSection (EW);
1511 }
1512 /****************************************************************
1513 * Set the cursor character as follows...
1514 * 1. Move backward to the newline character of the preceeding
1515 * line while counting the number of characters moved.
1516 * 2. Move backward to the first character of the preceeding
1517 * line.
1518 * 3. Move forward to position the cursor character at the same
1519 * column or at the newline character (which ever occurs
1520 * first).
1521 ****************************************************************/
1522 for (count = 1, EW->cursorChar--;
1523 EW->eText[EW->cursorChar] != Nl;
1524 EW->cursorChar--) count++;
1525 while (EW->cursorChar > 0) {
1526 if (EW->eText[EW->cursorChar-1] == Nl) break;
1527 EW->cursorChar--;
1528 }
1529 for (i = 1; i < count; i++) {
1530 if (EW->eText[EW->cursorChar] == Nl) break;
1531 EW->cursorChar++;
1532 }
1533 /****************************************************************
1534 * Update the percentage and cursor position.
1535 ****************************************************************/
1536 if (EW->ePct) UpdatePctString (EW->wid, EW->nChars + 1, 1,
1537 EW->cursorChar, EW->ePctRowN,
1538 EW->ePctColN);
1539 SetEditCursor (EW);
1540 }
1541 continue;
1542 }
1543 /********************************************************************
1544 * Check for left arrow key.
1545 ********************************************************************/
1546 if (EW->key == KB_LEFTARROW) {
1547 if (EW->cursorChar == 0)
1548 ring_bell ();
1549 else {
1550 if (EW->cursorChar == EW->firstChar) {
1551 for (EW->firstChar--; EW->firstChar > 0; EW->firstChar--) {
1552 if (EW->eText[EW->firstChar-1] == Nl) break;
1553 }
1554 DrawEditSection (EW);
1555 }
1556 EW->cursorChar--;
1557 if (EW->ePct) UpdatePctString (EW->wid, EW->nChars + 1, 1,
1558 EW->cursorChar, EW->ePctRowN,
1559 EW->ePctColN);
1560 SetEditCursor (EW);
1561 }
1562 continue;
1563 }
1564 /********************************************************************
1565 * Check for right arrow key.
1566 ********************************************************************/
1567 if (EW->key == KB_RIGHTARROW) {
1568 if (EW->eText[EW->cursorChar] == NUL)
1569 ring_bell ();
1570 else {
1571 if (EW->cursorRow == EW->eRowB &&
1572 EW->eText[EW->cursorChar] == Nl) {
1573 while (EW->eText[EW->firstChar] != Nl) EW->firstChar++;
1574 EW->firstChar++;
1575 DrawEditSection (EW);
1576 }
1577 EW->cursorChar++;
1578 if (EW->ePct) UpdatePctString (EW->wid, EW->nChars + 1, 1,
1579 EW->cursorChar, EW->ePctRowN,
1580 EW->ePctColN);
1581 SetEditCursor (EW);
1582 }
1583 continue;
1584 }
1585 /********************************************************************
1586 * Check for the RETURN key.
1587 ********************************************************************/
1588 if (EW->key == KB_RETURN) {
1589 if (EW->readOnly)
1590 ring_bell ();
1591 else {
1592 if (EW->nChars == EW->xChars) {
1593 EW->xChars += EW->nColS;
1594 EW->eText = cdf_ReallocateMemory (EW->eText,
1595 (size_t) (EW->xChars + 1),
1596 FatalError);
1597 }
1598 length = (int) strlen (&(EW->eText[EW->cursorChar]));
1599 memmove (&(EW->eText[EW->cursorChar+1]),
1600 &(EW->eText[EW->cursorChar]), (size_t) (length + 1));
1601 EW->eText[EW->cursorChar] = Nl;
1602 EW->nChars++;
1603 EW->cursorChar++;
1604 if (EW->cursorRow == EW->eRowB) {
1605 while (EW->eText[EW->firstChar] != Nl) EW->firstChar++;
1606 EW->firstChar++;
1607 }
1608 DrawEditSection (EW);
1609 if (EW->ePct) UpdatePctString (EW->wid, EW->nChars + 1, 1,
1610 EW->cursorChar, EW->ePctRowN,
1611 EW->ePctColN);
1612 SetEditCursor (EW);
1613 }
1614 continue;
1615 }
1616 /********************************************************************
1617 * Check for the DELETE key.
1618 ********************************************************************/
1619 if (EW->key == KB_DELETE) {
1620 if (EW->readOnly)
1621 ring_bell ();
1622 else {
1623 if (EW->cursorChar == 0)
1624 ring_bell ();
1625 else {
1626 length = (int) strlen (&(EW->eText[EW->cursorChar]));
1627 memmove (&(EW->eText[EW->cursorChar-1]),
1628 &(EW->eText[EW->cursorChar]), (size_t) (length + 1));
1629 EW->nChars--;
1630 if (EW->cursorChar == EW->firstChar) {
1631 for (EW->firstChar--; EW->firstChar > 0; EW->firstChar--) {
1632 if (EW->eText[EW->firstChar-1] == Nl) break;
1633 }
1634 }
1635 EW->cursorChar--;
1636 DrawEditSection (EW);
1637 if (EW->ePct) UpdatePctString (EW->wid, EW->nChars + 1, 1,
1638 EW->cursorChar, EW->ePctRowN,
1639 EW->ePctColN);
1640 SetEditCursor (EW);
1641 }
1642 }
1643 continue;
1644 }
1645 /********************************************************************
1646 * Check for the toggle insert/overstrike mode key.
1647 ********************************************************************/
1648 if (EW->key == EW->TOGGLEkey) {
1649 if (EW->readOnly)
1650 ring_bell ();
1651 else
1652 EW->insertMode = BOO(EW->insertMode,FALSE,TRUE);
1653 continue;
1654 }
1655 /********************************************************************
1656 * Check for the `refresh' key.
1657 ********************************************************************/
1658 if (EW->key == EW->REFRESHkey) {
1659 repaint_screen ();
1660 continue;
1661 }
1662 /********************************************************************
1663 * Check for a printable character.
1664 ********************************************************************/
1665 if (Printable(EW->key)) {
1666 if (EW->readOnly)
1667 ring_bell ();
1668 else {
1669 if (EW->insertMode ||
1670 EW->eText[EW->cursorChar] == Nl || /* If over- */
1671 EW->eText[EW->cursorChar] == NUL) { /* strike mode. */
1672 if (EW->nChars == EW->xChars) {
1673 EW->xChars += EW->nColS;
1674 EW->eText = cdf_ReallocateMemory (EW->eText,
1675 (size_t) (EW->xChars + 1),
1676 FatalError);
1677 }
1678 length = (int) strlen (&(EW->eText[EW->cursorChar]));
1679 memmove (&(EW->eText[EW->cursorChar+1]),
1680 &(EW->eText[EW->cursorChar]), (size_t) (length + 1));
1681 EW->eText[EW->cursorChar] = (char) EW->key;
1682 EW->nChars++;
1683 }
1684 else
1685 EW->eText[EW->cursorChar] = (char) EW->key;
1686 DrawEditSection (EW);
1687 if (EW->cursorCol < EW->nColS) EW->cursorChar++;
1688 if (EW->ePct) UpdatePctString (EW->wid, EW->nChars + 1, 1,
1689 EW->cursorChar, EW->ePctRowN,
1690 EW->ePctColN);
1691 SetEditCursor (EW);
1692 }
1693 continue;
1694 }
1695 /********************************************************************
1696 * Illegal key, ring the bell.
1697 ********************************************************************/
1698 ring_bell ();
1699 }
1700 }
1701 }
1702 va_end (ap);
1703 return FALSE; /* Illegal operation. */
1704 }
1705
1706 /******************************************************************************
1707 * DrawEditSection.
1708 ******************************************************************************/
1709
DrawEditSection(EW)1710 static void DrawEditSection (EW)
1711 struct EditWindowStruct *EW;
1712 {
1713 char *charPtr = &(EW->eText[EW->firstChar]);
1714 int rowN = EW->eRowT, length;
1715 for (;;) {
1716 char *nextNL = strchr (charPtr, Nl);
1717 if (nextNL == NULL) {
1718 length = (int) strlen (charPtr);
1719 if (length > 0) {
1720 put_chars (EW->wid, charPtr, MINIMUM(length,EW->nColS), rowN, 1,
1721 FALSE, NORMAL);
1722 if (length < EW->nColS) erase_display (EW->wid, rowN, length + 1,
1723 rowN, EW->nColS);
1724 rowN++;
1725 }
1726 break;
1727 }
1728 length = (int) (nextNL - charPtr);
1729 put_chars (EW->wid, charPtr, MINIMUM(length,EW->nColS), rowN, 1, FALSE,
1730 NORMAL);
1731 if (length < EW->nColS) erase_display (EW->wid, rowN, length + 1,
1732 rowN, EW->nColS);
1733 rowN++;
1734 if (rowN > EW->eRowB) break;
1735 charPtr = nextNL + 1;
1736 }
1737 if (rowN <= EW->eRowB) erase_display (EW->wid, rowN, 1,
1738 EW->eRowB, EW->nColS);
1739 return;
1740 }
1741
1742 /******************************************************************************
1743 * SetEditCursor.
1744 ******************************************************************************/
1745
SetEditCursor(EW)1746 static void SetEditCursor (EW)
1747 struct EditWindowStruct *EW;
1748 {
1749 int charN;
1750 EW->cursorRow = EW->eRowT;
1751 EW->cursorCol = 0;
1752 for (charN = EW->firstChar; charN <= EW->cursorChar; charN++) {
1753 EW->cursorCol++;
1754 if (EW->eText[charN] == Nl && charN < EW->cursorChar) {
1755 EW->cursorCol = 0;
1756 EW->cursorRow++;
1757 }
1758 }
1759 set_cursor_abs (EW->wid, EW->cursorRow, EW->cursorCol);
1760 return;
1761 }
1762
1763 /******************************************************************************
1764 * FieldWindow.
1765 *
1766 * Header section (optional).
1767 * Fields section (scrollable) containing one or more fields.
1768 * Trailer section (optional).
1769 *
1770 ******************************************************************************/
1771
1772 #if defined(STDARG)
FieldWindow(int opT,...)1773 int FieldWindow (int opT, ...)
1774 #else
1775 int FieldWindow (va_alist)
1776 va_dcl
1777 #endif
1778 {
1779 int op; /* Operation to perform (eg. create new menu). */
1780 struct FieldWindowStruct *FW;
1781 /* Menu configuration. */
1782 va_list ap;
1783 /***************************************************************************
1784 * Start variable-length argument list scanning.
1785 ***************************************************************************/
1786 #if defined(STDARG)
1787 va_start (ap, opT);
1788 op = opT;
1789 #else
1790 VA_START (ap);
1791 op = va_arg (ap, int);
1792 #endif
1793 FW = va_arg (ap, struct FieldWindowStruct *);
1794 /***************************************************************************
1795 * Perform desired operation. Some operations wait for user input (by
1796 * falling through the `switch' statement).
1797 ***************************************************************************/
1798 switch (op) {
1799 /*************************************************************************
1800 * Check for new/modified menu.
1801 *************************************************************************/
1802 case NEWfw:
1803 case UPDATEfw: {
1804 int nSections; /* Number of sections on window. */
1805 int nHorizLines; /* Number of horizontal lines needed. At
1806 most 2 horizontal lines will be needed
1807 to separate the 3 sections. */
1808 int horizRows[2]; /* Rows at which to draw the horizontal
1809 lines. */
1810 int horizLineN; /* Horizontal line number. */
1811 int xRow; /* Used when determining starting rows for
1812 the various sections. */
1813 /***********************************************************************
1814 * Get remaining arguments.
1815 ***********************************************************************/
1816 FW->fieldN = va_arg (ap, int);
1817 FW->insert = va_arg (ap, Logical);
1818 va_end (ap);
1819 /***********************************************************************
1820 * Validate menu.
1821 ***********************************************************************/
1822 if (FW->NfRows < 1) return FALSE;
1823 /***********************************************************************
1824 * Turn on cursor.
1825 ***********************************************************************/
1826 set_cursor_mode (CURSORon);
1827 /***********************************************************************
1828 * Calculate positions.
1829 ***********************************************************************/
1830 if (op == NEWfw) {
1831 FW->nColS = FW->nColsTotal - 2;
1832 nSections = 0;
1833 nHorizLines = 0;
1834 /*********************************************************************
1835 * Start at row 1 (row 0 is top border line).
1836 *********************************************************************/
1837 xRow = 1;
1838 if (FW->NhLines > 0) {
1839 nSections++;
1840 FW->hRowT = xRow;
1841 FW->hRowB = FW->hRowT + FW->NhLines - 1;
1842 xRow += FW->NhLines + 1;
1843 }
1844 nSections++;
1845 FW->fRowT = xRow;
1846 FW->fRowB = FW->fRowT + FW->NfRows - 1;
1847 xRow += FW->NfRows + 1;
1848 if (nSections > 1) horizRows[nHorizLines++] = FW->fRowT - 1;
1849 if (FW->NtLines > 0) {
1850 nSections++;
1851 FW->tRowT = xRow;
1852 FW->tRowB = FW->tRowT + FW->NtLines - 1;
1853 xRow += FW->NtLines + 1;
1854 if (nSections > 1) horizRows[nHorizLines++] = FW->tRowT - 1;
1855 }
1856 FW->nRowsTotal = xRow;
1857 }
1858 /***********************************************************************
1859 * Create window?
1860 ***********************************************************************/
1861 begin_pasteboard_update ();
1862 if (op == NEWfw) {
1863 create_virtual_display (FW->nRowsTotal, FW->nColsTotal, &(FW->wid),
1864 BORDER, NORMAL);
1865 paste_virtual_display (FW->wid, FW->ULrow, FW->ULcol);
1866 }
1867 /***********************************************************************
1868 * If specified, write label to window. If this is an update operation,
1869 * first overwrite the existing label.
1870 ***********************************************************************/
1871 if (op == UPDATEfw) draw_horizontal_line (FW->wid, 0, 1, FW->nColS,
1872 NORMAL, FALSE);
1873 if (FW->label != NULL) {
1874 int len = (int) strlen(FW->label);
1875 if (len <= FW->nColS) {
1876 int nRemainChars = FW->nColS - len;
1877 int nCharsBefore = nRemainChars / 2;
1878 put_chars (FW->wid, FW->label, len, 0, nCharsBefore + 1, FALSE,
1879 REVERSE1);
1880 }
1881 }
1882 /***********************************************************************
1883 * If necessary, draw horizontal lines on window.
1884 ***********************************************************************/
1885 if (op == NEWfw) {
1886 for (horizLineN = 0; horizLineN < nHorizLines; horizLineN++) {
1887 draw_horizontal_line (FW->wid, horizRows[horizLineN], 0,
1888 FW->nColsTotal-1, NORMAL, TRUE);
1889 }
1890 }
1891 /***********************************************************************
1892 * If specified, write header section to window. If an update operation,
1893 * it is assumed that the number of lines has not changed.
1894 ***********************************************************************/
1895 if (FW->NhLines > 0) DrawSection (FW->wid, FW->hRowT, FW->hRowB, 0,
1896 FW->NhLines, FW->hLines, FW->nColS);
1897 /***********************************************************************
1898 * Write fields section to window. If an update operation, note that
1899 * the number of lines may have changed.
1900 ***********************************************************************/
1901 if (op == UPDATEfw) {
1902 if (FW->fUpTo != NULL) cdf_FreeMemory (FW->fUpTo, FatalError);
1903 if (FW->fDownTo != NULL) cdf_FreeMemory (FW->fDownTo, FatalError);
1904 if (FW->fLeftTo != NULL) cdf_FreeMemory (FW->fLeftTo, FatalError);
1905 if (FW->fRightTo != NULL) cdf_FreeMemory (FW->fRightTo, FatalError);
1906 }
1907 if (FW->nFields > 0) {
1908 size_t nBytes = FW->nFields * sizeof(int);
1909 FW->fUpTo = (int *) cdf_AllocateMemory (nBytes, FatalError);
1910 FW->fDownTo = (int *) cdf_AllocateMemory (nBytes, FatalError);
1911 FW->fLeftTo = (int *) cdf_AllocateMemory (nBytes, FatalError);
1912 FW->fRightTo = (int *) cdf_AllocateMemory (nBytes, FatalError);
1913 CalcItemDirections (FW->nFields, FW->NfLines, FW->fLineNs, FW->fCols,
1914 FW->fLens, FW->fDownTo, FW->fUpTo, FW->fLeftTo,
1915 FW->fRightTo);
1916 }
1917 else {
1918 FW->fUpTo = NULL;
1919 FW->fDownTo = NULL;
1920 FW->fLeftTo = NULL;
1921 FW->fRightTo = NULL;
1922 }
1923 if (FW->NfLines > FW->NfRows)
1924 FW->fScroll = TRUE;
1925 else
1926 FW->fScroll = FALSE;
1927 /***********************************************************************
1928 * Determine row number for current field. If this is an UPDATEfw
1929 * operation, try to keep the row number the same as it was (or as
1930 * close as possible).
1931 ***********************************************************************/
1932 if (FW->nFields > 0) {
1933 if (op == NEWfw)
1934 FW->fRowN = MinInt (FW->fRowT + FW->fLineNs[FW->fieldN], FW->fRowB);
1935 else {
1936 if (FW->fScroll) {
1937 int nLinesFromTop = FW->fLineNs[FW->fieldN];
1938 int nRowsFromTop = FW->fRowN - FW->fRowT;
1939 if (nLinesFromTop < nRowsFromTop)
1940 FW->fRowN -= nRowsFromTop - nLinesFromTop;
1941 else {
1942 int nLinesFromBot = (FW->NfLines-1) - FW->fLineNs[FW->fieldN];
1943 int nRowsFromBot = FW->fRowB - FW->fRowN;
1944 if (nLinesFromBot < nRowsFromBot)
1945 FW->fRowN += nRowsFromBot - nLinesFromBot;
1946 }
1947 }
1948 else
1949 FW->fRowN = FW->fRowT + FW->fLineNs[FW->fieldN];
1950 }
1951 }
1952 else
1953 FW->fRowN = FW->fRowT;
1954 /*********************************************************************
1955 * Draw fields section.
1956 *********************************************************************/
1957 DrawFieldsSection (FW);
1958 /*********************************************************************
1959 * Setup/display initial percentage indicator.
1960 *********************************************************************/
1961 if (FW->fPct) {
1962 int lineNt = FWtopRowLineN (FW);
1963 if (op == NEWfw) {
1964 FW->fPctRowN = FW->fRowB + 1;
1965 FW->fPctColN = FW->nColsTotal - 7;
1966 }
1967 UpdatePctString (FW->wid, FW->NfLines, FW->NfRows, lineNt,
1968 FW->fPctRowN, FW->fPctColN);
1969 }
1970 /***********************************************************************
1971 * If specified, write trailer section to window. If an update
1972 * operation, it is assumed that the number of lines has not changed.
1973 ***********************************************************************/
1974 if (FW->NtLines > 0) DrawSection (FW->wid, FW->tRowT, FW->tRowB, 0,
1975 FW->NtLines, FW->tLines, FW->nColS);
1976 /***********************************************************************
1977 * Update screen and place the cursor in the current field.
1978 ***********************************************************************/
1979 end_pasteboard_update ();
1980 FW->charN = 0;
1981 FW->leftCharN = 0;
1982 if (FW->nFields > 0) {
1983 set_cursor_abs (FW->wid, FW->fRowN, FW->fCols[FW->fieldN] + 1);
1984 }
1985 return TRUE;
1986 }
1987 /*************************************************************************
1988 * Check for a beep request.
1989 *************************************************************************/
1990 case BEEPfw:
1991 ring_bell ();
1992 va_end (ap);
1993 return TRUE;
1994 /*************************************************************************
1995 * Check if menu should be deleted.
1996 *************************************************************************/
1997 case DELETEfw:
1998 if (FW->fUpTo != NULL) cdf_FreeMemory (FW->fUpTo, FatalError);
1999 if (FW->fDownTo != NULL) cdf_FreeMemory (FW->fDownTo, FatalError);
2000 if (FW->fLeftTo != NULL) cdf_FreeMemory (FW->fLeftTo, FatalError);
2001 if (FW->fRightTo != NULL) cdf_FreeMemory (FW->fRightTo, FatalError);
2002 delete_virtual_display (FW->wid);
2003 va_end (ap);
2004 return TRUE;
2005 /*************************************************************************
2006 * Check if menu should be erased (but remain in existence).
2007 *************************************************************************/
2008 case UNDISPLAYfw:
2009 unpaste_virtual_display (FW->wid);
2010 va_end (ap);
2011 return TRUE;
2012 /*************************************************************************
2013 * Check if menu should be redisplayed (but don't wait for input - a call
2014 * with `op = READfw' should be made next).
2015 *************************************************************************/
2016 case REDISPLAYfw:
2017 set_cursor_mode (CURSORon);
2018 paste_virtual_display (FW->wid, FW->ULrow, FW->ULcol);
2019 va_end (ap);
2020 return TRUE;
2021 /*************************************************************************
2022 * Get next input. The cursor is positioned first in case it had been
2023 * moved.
2024 *************************************************************************/
2025 case READfw: {
2026 int colN;
2027 if (FW->nFields < 1) return FALSE;
2028 set_cursor_mode (CURSORon);
2029 colN = FW->fCols[FW->fieldN] + (FW->charN - FW->leftCharN) + 1;
2030 set_cursor_abs (FW->wid, FW->fRowN, colN);
2031 for (;;) {
2032 read_input (
2033 #if defined(CURSESui)
2034 FW->wid,
2035 #endif
2036 &(FW->key), PASSTHRUri, TRUE);
2037 /********************************************************************
2038 * Check for an exit key. If no exit keys were specified, any key
2039 * causes an exit.
2040 ********************************************************************/
2041 if (FW->exitChars[0] == NUL) {
2042 va_end (ap);
2043 return TRUE;
2044 }
2045 else {
2046 int charN;
2047 for (charN = 0; FW->exitChars[charN] != NUL; charN++)
2048 if (FW->key == FW->exitChars[charN]) {
2049 va_end (ap);
2050 return TRUE;
2051 }
2052 }
2053 /********************************************************************
2054 * Check for next-screen key.
2055 ********************************************************************/
2056 if (FW->key == FW->NSkey) {
2057 begin_pasteboard_update ();
2058 NextScreen (FW->NfRows, FW->NfLines, FW->fLineNs, FW->fDownTo,
2059 FW->fRowB, FW->fRowT, FW->fScroll, &(FW->fieldN),
2060 &(FW->fRowN));
2061 DrawFieldsSection (FW);
2062 if (FW->fPct) UpdatePctString (FW->wid, FW->NfLines, FW->NfRows,
2063 FWtopRowLineN(FW), FW->fPctRowN,
2064 FW->fPctColN);
2065 end_pasteboard_update ();
2066 FW->charN = 0;
2067 FW->leftCharN = 0;
2068 set_cursor_abs (FW->wid, FW->fRowN, FW->fCols[FW->fieldN] + 1);
2069 continue;
2070 }
2071 /********************************************************************
2072 * Check for prev-screen key.
2073 ********************************************************************/
2074 if (FW->key == FW->PSkey) {
2075 begin_pasteboard_update ();
2076 PrevScreen (FW->NfRows, FW->fLineNs, FW->fUpTo, FW->fRowT,
2077 FW->fScroll, &(FW->fRowN), &(FW->fieldN));
2078 DrawFieldsSection (FW);
2079 if (FW->fPct) UpdatePctString (FW->wid, FW->NfLines, FW->NfRows,
2080 FWtopRowLineN(FW), FW->fPctRowN,
2081 FW->fPctColN);
2082 end_pasteboard_update ();
2083 FW->charN = 0;
2084 FW->leftCharN = 0;
2085 set_cursor_abs (FW->wid, FW->fRowN, FW->fCols[FW->fieldN] + 1);
2086 continue;
2087 }
2088 /********************************************************************
2089 * Check for down field key.
2090 ********************************************************************/
2091 if (FW->key == FW_DOWN_FIELD || FW->key == FW_DOWN_FIELDx) {
2092 begin_pasteboard_update ();
2093 DownArrow (FW->fLineNs, FW->fDownTo, FW->fRowT, FW->fRowB,
2094 FW->fScroll, &(FW->fRowN), &(FW->fieldN));
2095 DrawFieldsSection (FW);
2096 if (FW->fPct) UpdatePctString (FW->wid, FW->NfLines, FW->NfRows,
2097 FWtopRowLineN(FW), FW->fPctRowN,
2098 FW->fPctColN);
2099 end_pasteboard_update ();
2100 FW->charN = 0;
2101 FW->leftCharN = 0;
2102 set_cursor_abs (FW->wid, FW->fRowN, FW->fCols[FW->fieldN] + 1);
2103 continue;
2104 }
2105 /********************************************************************
2106 * Check for up field key.
2107 ********************************************************************/
2108 if (FW->key == FW_UP_FIELD || FW->key == FW_UP_FIELDx) {
2109 begin_pasteboard_update ();
2110 UpArrow (FW->NfLines, FW->fLineNs, FW->fUpTo, FW->fRowT,
2111 FW->fRowB, FW->fScroll, &(FW->fRowN), &(FW->fieldN));
2112 DrawFieldsSection (FW);
2113 if (FW->fPct) UpdatePctString (FW->wid, FW->NfLines, FW->NfRows,
2114 FWtopRowLineN(FW), FW->fPctRowN,
2115 FW->fPctColN);
2116 end_pasteboard_update ();
2117 FW->charN = 0;
2118 FW->leftCharN = 0;
2119 set_cursor_abs (FW->wid, FW->fRowN, FW->fCols[FW->fieldN] + 1);
2120 continue;
2121 }
2122 /********************************************************************
2123 * Check for left field key.
2124 ********************************************************************/
2125 if (FW->key == FW_LEFT_FIELD || FW->key == FW_LEFT_FIELDx) {
2126 FW->fieldN = FW->fLeftTo[FW->fieldN];
2127 FW->charN = 0;
2128 FW->leftCharN = 0;
2129 set_cursor_abs (FW->wid, FW->fRowN, FW->fCols[FW->fieldN] + 1);
2130 continue;
2131 }
2132 /********************************************************************
2133 * Check for right field key.
2134 ********************************************************************/
2135 if (FW->key == FW_RIGHT_FIELD || FW->key == FW_RIGHT_FIELDx) {
2136 FW->fieldN = FW->fRightTo[FW->fieldN];
2137 FW->charN = 0;
2138 FW->leftCharN = 0;
2139 set_cursor_abs (FW->wid, FW->fRowN, FW->fCols[FW->fieldN] + 1);
2140 continue;
2141 }
2142 /********************************************************************
2143 * Check for left character key.
2144 ********************************************************************/
2145 if (FW->key == FW_LEFT_CHAR || FW->key == FW_LEFT_CHARx) {
2146 if (FW->charN > 0) {
2147 int colN, len; char *ptr;
2148 if (FW->charN == FW->leftCharN) {
2149 FW->leftCharN--;
2150 ptr = &(FW->fields[FW->fieldN][FW->leftCharN]);
2151 len = (int) strlen(ptr);
2152 put_chars (FW->wid, ptr, MINIMUM(len,FW->fLens[FW->fieldN]),
2153 FW->fRowN, FW->fCols[FW->fieldN] + 1, FALSE, NORMAL);
2154 }
2155 FW->charN--;
2156 colN = FW->fCols[FW->fieldN] + (FW->charN - FW->leftCharN);
2157 set_cursor_abs (FW->wid, FW->fRowN, colN + 1);
2158 }
2159 else
2160 ring_bell ();
2161 continue;
2162 }
2163 /********************************************************************
2164 * Check for right character key.
2165 ********************************************************************/
2166 if (FW->key == FW_RIGHT_CHAR || FW->key == FW_RIGHT_CHARx) {
2167 int fieldLen = (int) strlen(FW->fields[FW->fieldN]);
2168 if (FW->charN < fieldLen) {
2169 int colN, cursorPos = FW->charN - FW->leftCharN + 1;
2170 if (cursorPos == FW->fLens[FW->fieldN]) {
2171 char *ptr = &(FW->fields[FW->fieldN][FW->leftCharN+1]);
2172 if (FW->charN == fieldLen - 1) {
2173 int count = FW->fLens[FW->fieldN] - 1;
2174 put_chars (FW->wid, ptr, count, FW->fRowN,
2175 FW->fCols[FW->fieldN] + 1, FALSE, NORMAL);
2176 colN = FW->fCols[FW->fieldN] + count;
2177 put_chars (FW->wid, " ", 1, FW->fRowN, colN + 1,
2178 FALSE, NORMAL);
2179 }
2180 else {
2181 put_chars (FW->wid, ptr, FW->fLens[FW->fieldN], FW->fRowN,
2182 FW->fCols[FW->fieldN] + 1, FALSE, NORMAL);
2183 }
2184 FW->leftCharN++;
2185 }
2186 FW->charN++;
2187 colN = FW->fCols[FW->fieldN] + (FW->charN - FW->leftCharN);
2188 set_cursor_abs (FW->wid, FW->fRowN, colN + 1);
2189 }
2190 else
2191 ring_bell ();
2192 continue;
2193 }
2194 /********************************************************************
2195 * Check for delete key.
2196 ********************************************************************/
2197 if (FW->key == KB_DELETE) {
2198 if (FW->charN > 0) {
2199 if (FW->charN == FW->leftCharN) {
2200 char *ptr = &(FW->fields[FW->fieldN][FW->charN]);
2201 memmove (ptr - 1, ptr, strlen(ptr) + 1);
2202 FW->charN--;
2203 FW->leftCharN--;
2204 }
2205 else {
2206 char *ptr;
2207 ptr = &(FW->fields[FW->fieldN][FW->charN]);
2208 memmove (ptr - 1, ptr, strlen(ptr) + 1);
2209 FW->charN--;
2210 DrawField (FW);
2211 }
2212 }
2213 else
2214 ring_bell ();
2215 continue;
2216 }
2217 /********************************************************************
2218 * Check for the `refresh' key.
2219 ********************************************************************/
2220 if (FW->key == FW->refreshChar) {
2221 repaint_screen ();
2222 continue;
2223 }
2224 /********************************************************************
2225 * Check for the toggle insert/overstrike key.
2226 ********************************************************************/
2227 if (FW->key == FW->toggleKey) {
2228 FW->insert = BOO(FW->insert,FALSE,TRUE);
2229 continue;
2230 }
2231 /********************************************************************
2232 * Character to insert/overstrike.
2233 ********************************************************************/
2234 if (Printable(FW->key)) {
2235 if (FW->insert) {
2236 int len = (int) strlen(FW->fields[FW->fieldN]);
2237 if (len < FW->fMaxs[FW->fieldN]) {
2238 char *ptr = &(FW->fields[FW->fieldN][FW->charN]);
2239 int len = (int) strlen(ptr);
2240 memmove (ptr + 1, ptr, len + 1);
2241 *ptr = (char) FW->key;
2242 if (FW->charN - FW->leftCharN == FW->fLens[FW->fieldN] - 1) {
2243 FW->leftCharN++;
2244 }
2245 FW->charN++;
2246 DrawField (FW);
2247 }
2248 else
2249 ring_bell ();
2250 }
2251 else {
2252 if (FW->charN < FW->fMaxs[FW->fieldN]) {
2253 int len = (int) strlen(FW->fields[FW->fieldN]);
2254 char *ptr = &(FW->fields[FW->fieldN][FW->charN]);
2255 *ptr = (char) FW->key;
2256 if (FW->charN == len) *(ptr+1) = NUL;
2257 if (FW->charN - FW->leftCharN == FW->fLens[FW->fieldN] - 1) {
2258 FW->leftCharN++;
2259 }
2260 FW->charN++;
2261 DrawField (FW);
2262 }
2263 else
2264 ring_bell ();
2265 }
2266 continue;
2267 }
2268 /********************************************************************
2269 * Illegal key, ring the bell.
2270 ********************************************************************/
2271 ring_bell ();
2272 }
2273 }
2274 }
2275 va_end (ap);
2276 return FALSE; /* Illegal operation. */
2277 }
2278
2279 /******************************************************************************
2280 * DrawField.
2281 ******************************************************************************/
2282
DrawField(FW)2283 static void DrawField (FW)
2284 struct FieldWindowStruct *FW;
2285 {
2286 char *ptr = &(FW->fields[FW->fieldN][FW->leftCharN]);
2287 int i, colN, len = (int) strlen(ptr);
2288 put_chars (FW->wid, ptr, MINIMUM(len,FW->fLens[FW->fieldN]),
2289 FW->fRowN, FW->fCols[FW->fieldN] + 1, FALSE, NORMAL);
2290 for (i = len; i < FW->fLens[FW->fieldN]; i++) {
2291 put_chars (FW->wid, " ", 1, FW->fRowN,
2292 FW->fCols[FW->fieldN] + i + 1, FALSE, NORMAL);
2293 }
2294 colN = FW->fCols[FW->fieldN] + (FW->charN - FW->leftCharN);
2295 set_cursor_abs (FW->wid, FW->fRowN, colN + 1);
2296 return;
2297 }
2298
2299 /******************************************************************************
2300 * DrawFieldsSection.
2301 ******************************************************************************/
2302
DrawFieldsSection(FW)2303 static void DrawFieldsSection (FW)
2304 struct FieldWindowStruct *FW; /* Pointer to FieldWindow structure. */
2305 {
2306 size_t len; int i, rowN, lineN, fieldN; char line[SCREEN_WIDTH+1];
2307 for (rowN = FW->fRowT, lineN = FWtopRowLineN(FW);
2308 rowN <= FW->fRowB && lineN < FW->NfLines; rowN++, lineN++) {
2309 strcpyX (line, FW->fLines[lineN], SCREEN_WIDTH);
2310 for (fieldN = 0; fieldN < FW->nFields; fieldN++) {
2311 if (FW->fLineNs[fieldN] == lineN) {
2312 len = (int) strlen(FW->fields[fieldN]);
2313 for (i = 0; i < FW->fLens[fieldN]; i++) {
2314 if (i < (int) len)
2315 line[FW->fCols[fieldN]+i] = FW->fields[fieldN][i];
2316 else
2317 line[FW->fCols[fieldN]+i] = ' ';
2318 }
2319 }
2320 }
2321 len = (int) strlen(line);
2322 put_chars (FW->wid, line, MINIMUM(FW->nColS,(int)len), rowN, 1,
2323 FALSE, NORMAL);
2324 if ((int)len < FW->nColS)
2325 erase_display (FW->wid, rowN, (int)len + 1, rowN, FW->nColS);
2326 }
2327 if (rowN <= FW->fRowB) erase_display (FW->wid, rowN, 1, FW->fRowB, FW->nColS);
2328 return;
2329 }
2330
2331 /******************************************************************************
2332 * CalcItemDirections.
2333 ******************************************************************************/
2334
CalcItemDirections(nItems,NiLines,iLineNs,iCols,iLens,iDownTo,iUpTo,iLeftTo,iRightTo)2335 static void CalcItemDirections (nItems, NiLines, iLineNs, iCols, iLens,
2336 iDownTo, iUpTo, iLeftTo, iRightTo)
2337 int nItems;
2338 int NiLines;
2339 int *iLineNs;
2340 int *iCols;
2341 int *iLens;
2342 int *iDownTo;
2343 int *iUpTo;
2344 int *iLeftTo;
2345 int *iRightTo;
2346 {
2347 int *center, i;
2348 /***************************************************************************
2349 * Allocate and calculate center point for each item.
2350 ***************************************************************************/
2351 center = (int *) cdf_AllocateMemory (nItems * sizeof(int),
2352 FatalError);
2353 for (i = 0; i < nItems; i++) {
2354 center[i] = iCols[i] + (iLens[i] / 2);
2355 }
2356 /***************************************************************************
2357 * Calculate directions for each item.
2358 ***************************************************************************/
2359 for (i = 0; i < nItems; i++) {
2360 /************************************************************************
2361 * Calculate down direction.
2362 ************************************************************************/
2363 iDownTo[i] = i;
2364 if (NiLines > 1 && nItems > 1) {
2365 int toLineN, mostOff, j;
2366 int fromLineN = iLineNs[i];
2367 for (j = (i+1) % nItems, toLineN = -1; j != i; j = (j+1) % nItems) {
2368 int lineNt = iLineNs[j];
2369 if (lineNt != fromLineN)
2370 if (toLineN == -1) {
2371 iDownTo[i] = j;
2372 toLineN = lineNt;
2373 mostOff = DIFF(center[i],center[j]);
2374 }
2375 else
2376 if (lineNt == toLineN) {
2377 int offBy = DIFF(center[i],center[j]);
2378 if (offBy < mostOff) {
2379 iDownTo[i] = j;
2380 mostOff = offBy;
2381 }
2382 }
2383 else
2384 break; /* No more items on `toLineN'. */
2385 }
2386 }
2387 /************************************************************************
2388 * Calculate up direction.
2389 ************************************************************************/
2390 iUpTo[i] = i;
2391 if (NiLines > 1 && nItems > 1) {
2392 int toLineN, mostOff, j;
2393 int fromLineN = iLineNs[i];
2394 for (j = (i == 0 ? nItems-1 : i-1), toLineN = -1;
2395 j != i; j = (j == 0 ? nItems-1 : j-1)) {
2396 int lineNt = iLineNs[j];
2397 if (lineNt != fromLineN)
2398 if (toLineN == -1) {
2399 iUpTo[i] = j;
2400 toLineN = lineNt;
2401 mostOff = DIFF(center[i],center[j]);
2402 }
2403 else
2404 if (lineNt == toLineN) {
2405 int offBy = DIFF(center[i],center[j]);
2406 if (offBy < mostOff) {
2407 iUpTo[i] = j;
2408 mostOff = offBy;
2409 }
2410 }
2411 else
2412 break; /* No more items on `toLineN'. */
2413 }
2414 }
2415 /************************************************************************
2416 * Calculate left direction. First check for the nearest item to the
2417 * left. If none found, check for the farthest item to the right (if
2418 * none found, going left stays at the same item).
2419 ************************************************************************/
2420 iLeftTo[i] = i;
2421 if (nItems > 1) {
2422 int toLeftLineN = (i > 0 ? iLineNs[i-1] : -1), j;
2423 if (toLeftLineN == iLineNs[i])
2424 iLeftTo[i] = i - 1;
2425 else
2426 for (j = i+1; j < nItems; j++)
2427 if (iLineNs[j] == iLineNs[i])
2428 iLeftTo[i] = j;
2429 else
2430 break;
2431 }
2432 /************************************************************************
2433 * Calculate right direction. First check for the nearest item to the
2434 * right. If none found, check for the farthest item to the left (if
2435 * none found, going right stays at the same item).
2436 ************************************************************************/
2437 iRightTo[i] = i;
2438 if (nItems > 1) {
2439 int toRightLineN = (i < nItems-1 ? iLineNs[i+1] : -1), j;
2440 if (toRightLineN == iLineNs[i])
2441 iRightTo[i] = i + 1;
2442 else
2443 for (j = i-1; j >= 0; j--)
2444 if (iLineNs[j] == iLineNs[i])
2445 iRightTo[i] = j;
2446 else
2447 break;
2448 }
2449 }
2450 cdf_FreeMemory (center, FatalError);
2451 return;
2452 }
2453
2454 /******************************************************************************
2455 * UpdatePctString.
2456 ******************************************************************************/
2457
UpdatePctString(wid,nLines,nRows,topRowLineN,rowN,colN)2458 static void UpdatePctString (wid, nLines, nRows, topRowLineN, rowN, colN)
2459 WINDOWid wid;
2460 int nLines;
2461 int nRows;
2462 int topRowLineN;
2463 int rowN;
2464 int colN;
2465 {
2466 char pct[MAX_PCT_LEN+1];
2467 if (nLines <= nRows)
2468 strcpyX (pct, " All ", MAX_PCT_LEN);
2469 else
2470 if (topRowLineN == 0)
2471 strcpyX (pct, " Top ", MAX_PCT_LEN);
2472 else
2473 if (topRowLineN == nLines - nRows)
2474 strcpyX (pct, " End ", MAX_PCT_LEN);
2475 else {
2476 sprintf (pct, "%3d%% ", (int)
2477 ((100.0 * (((float) topRowLineN) / (nLines - nRows))) + 0.5));
2478 }
2479 put_chars (wid, pct, (int) strlen(pct), rowN, colN, FALSE, NORMAL);
2480 return;
2481 }
2482
2483 /******************************************************************************
2484 * DrawSection.
2485 ******************************************************************************/
2486
DrawSection(wid,rowT,rowB,topRowLineN,nLines,lineS,nColS)2487 static void DrawSection (wid, rowT, rowB, topRowLineN, nLines, lineS, nColS)
2488 WINDOWid wid;
2489 int rowT; /* Top row number. */
2490 int rowB; /* Bottom row number. */
2491 int topRowLineN; /* Line number to be displayed in top row. */
2492 int nLines; /* Number of lines (may be greater than the number of
2493 available rows). */
2494 char **lineS; /* Lines to be displayed. Capital `S' because of the
2495 IBM RS6000. */
2496 int nColS; /* Number of available columns (first character of a
2497 line is displayed in column one [1]). */
2498 {
2499 size_t len;
2500 int rowN, lineN;
2501 for (rowN = rowT, lineN = topRowLineN;
2502 rowN <= rowB && lineN < nLines; rowN++, lineN++) {
2503 len = strlen(lineS[lineN]);
2504 put_chars (wid, lineS[lineN], MINIMUM(nColS,(int)len), rowN, 1,
2505 FALSE, NORMAL);
2506 if ((int)len < nColS)
2507 erase_display (wid, rowN, (int)len + 1, rowN, nColS);
2508 }
2509 if (rowN <= rowB) erase_display (wid, rowN, 1, rowB, nColS);
2510 return;
2511 }
2512
2513 /******************************************************************************
2514 * NextScreen.
2515 ******************************************************************************/
2516
NextScreen(NiRows,NiLines,iLineNs,iDownTo,iRowB,iRowT,iScroll,itemN,iRowN)2517 static void NextScreen (NiRows, NiLines, iLineNs, iDownTo, iRowB, iRowT,
2518 iScroll, itemN, iRowN)
2519 int NiRows;
2520 int NiLines;
2521 int *iLineNs;
2522 int *iDownTo;
2523 int iRowB;
2524 int iRowT;
2525 Logical iScroll;
2526 int *itemN;
2527 int *iRowN;
2528 {
2529 int oldLineN = iLineNs[*itemN];
2530 int maxLineN = MinInt (oldLineN + NiRows, NiLines - 1);
2531 for (;;) {
2532 int itemNt = iDownTo[*itemN];
2533 int lineNt = iLineNs[itemNt];
2534 if (lineNt <= maxLineN && lineNt > oldLineN)
2535 *itemN = itemNt;
2536 else
2537 break;
2538 }
2539 if (iScroll) {
2540 int linesToEnd = (NiLines - 1) - iLineNs[*itemN];
2541 if (*iRowN + linesToEnd < iRowB) *iRowN = iRowB - linesToEnd;
2542 }
2543 else
2544 *iRowN = iRowT + iLineNs[*itemN];
2545 return;
2546 }
2547
2548 /******************************************************************************
2549 * PrevScreen.
2550 ******************************************************************************/
2551
PrevScreen(NiRows,iLineNs,iUpTo,iRowT,iScroll,iRowN,itemN)2552 static void PrevScreen (NiRows, iLineNs, iUpTo, iRowT, iScroll, iRowN, itemN)
2553 int NiRows;
2554 int *iLineNs;
2555 int *iUpTo;
2556 int iRowT;
2557 Logical iScroll;
2558 int *iRowN;
2559 int *itemN;
2560 {
2561 int oldLineN = iLineNs[*itemN];
2562 int minLineN = MaxInt (oldLineN - NiRows, 0);
2563 for (;;) {
2564 int itemNt = iUpTo[*itemN];
2565 int lineNt = iLineNs[itemNt];
2566 if (lineNt >= minLineN && lineNt < oldLineN)
2567 *itemN = itemNt;
2568 else
2569 break;
2570 }
2571 if (iScroll) {
2572 int linesToBeg = iLineNs[*itemN];
2573 if (*iRowN - linesToBeg > iRowT) *iRowN = iRowT + linesToBeg;
2574 }
2575 else
2576 *iRowN = iRowT + iLineNs[*itemN];
2577 return;
2578 }
2579
2580 /******************************************************************************
2581 * DownArrow.
2582 ******************************************************************************/
2583
DownArrow(iLineNs,iDownTo,iRowT,iRowB,iScroll,iRowN,itemN)2584 static void DownArrow (iLineNs, iDownTo, iRowT, iRowB, iScroll, iRowN, itemN)
2585 int *iLineNs;
2586 int *iDownTo;
2587 int iRowT;
2588 int iRowB;
2589 Logical iScroll;
2590 int *iRowN;
2591 int *itemN;
2592 {
2593 int oldLineN = iLineNs[*itemN];
2594 *itemN = iDownTo[*itemN];
2595 if (iScroll) {
2596 int nLinesDown = iLineNs[*itemN] - oldLineN;
2597 if (nLinesDown < 0)
2598 *iRowN = iRowT + iLineNs[*itemN];
2599 else
2600 *iRowN = MINIMUM (*iRowN + nLinesDown, iRowB);
2601 }
2602 else
2603 *iRowN = iRowT + iLineNs[*itemN];
2604 return;
2605 }
2606
2607 /******************************************************************************
2608 * UpArrow.
2609 ******************************************************************************/
2610
UpArrow(NiLines,iLineNs,iUpTo,iRowT,iRowB,iScroll,iRowN,itemN)2611 static void UpArrow (NiLines, iLineNs, iUpTo, iRowT, iRowB, iScroll, iRowN,
2612 itemN)
2613 int NiLines;
2614 int *iLineNs;
2615 int *iUpTo;
2616 int iRowT;
2617 int iRowB;
2618 Logical iScroll;
2619 int *iRowN;
2620 int *itemN;
2621 {
2622 int oldLineN = iLineNs[*itemN];
2623 *itemN = iUpTo[*itemN];
2624 if (iScroll) {
2625 int nLinesUp = oldLineN - iLineNs[*itemN];
2626 if (nLinesUp < 0) {
2627 int nLinesFromBot = (NiLines - 1) - iLineNs[*itemN];
2628 *iRowN = iRowB - nLinesFromBot;
2629 }
2630 else
2631 *iRowN = MaxInt (*iRowN - nLinesUp, iRowT);
2632 }
2633 else
2634 *iRowN = iRowT + iLineNs[*itemN];
2635 return;
2636 }
2637
2638 /******************************************************************************
2639 * IWtopRowLineN.
2640 ******************************************************************************/
2641
IWtopRowLineN(IW)2642 static int IWtopRowLineN (IW)
2643 struct ItemWindowStruct *IW;
2644 {
2645 return BOO(IW->nItems > 0,
2646 IW->iLineNs[IW->itemN] - (IW->iRowN - IW->iRowT), 0);
2647 }
2648
2649 /******************************************************************************
2650 * FWtopRowLineN.
2651 ******************************************************************************/
2652
FWtopRowLineN(FW)2653 static int FWtopRowLineN (FW)
2654 struct FieldWindowStruct *FW;
2655 {
2656 return BOO(FW->nFields > 0,
2657 FW->fLineNs[FW->fieldN] - (FW->fRowN - FW->fRowT), 0);
2658 }
2659
2660 /******************************************************************************
2661 * AllocIW.
2662 ******************************************************************************/
2663
AllocIW(IW,nItems,NiLines,iLineNchars,fatalFnc)2664 void AllocIW (IW, nItems, NiLines, iLineNchars, fatalFnc)
2665 struct ItemWindowStruct *IW;
2666 int nItems;
2667 int NiLines;
2668 int iLineNchars;
2669 void (*fatalFnc) PROTOARGs((char *msg));
2670 {
2671 IW->nItems = nItems;
2672 if (IW->nItems > 0) {
2673 IW->iLineNs = (int *) cdf_AllocateMemory (IW->nItems * sizeof(int),
2674 fatalFnc);
2675 IW->iCols = (int *) cdf_AllocateMemory (IW->nItems * sizeof(int),
2676 fatalFnc);
2677 IW->iLens = (int *) cdf_AllocateMemory (IW->nItems * sizeof(int),
2678 fatalFnc);
2679 }
2680 IW->NiLines = NiLines;
2681 if (IW->NiLines > 0) {
2682 int lineN, i;
2683 IW->iLines = (char **) cdf_AllocateMemory (IW->NiLines * sizeof(char *),
2684 fatalFnc);
2685 for (lineN = 0; lineN < IW->NiLines; lineN++) {
2686 IW->iLines[lineN] = (char *) cdf_AllocateMemory (iLineNchars+1,
2687 fatalFnc);
2688 for (i = 0; i < iLineNchars; i++) IW->iLines[lineN][i] = ' ';
2689 IW->iLines[lineN][iLineNchars] = NUL;
2690 }
2691 }
2692 return;
2693 }
2694
2695 /******************************************************************************
2696 * AllocFW.
2697 ******************************************************************************/
2698
AllocFW(FW,nFields,NfLines,fLineNchars,fatalFnc)2699 void AllocFW (FW, nFields, NfLines, fLineNchars, fatalFnc)
2700 struct FieldWindowStruct *FW;
2701 int nFields;
2702 int NfLines;
2703 int fLineNchars;
2704 void (*fatalFnc) PROTOARGs((char *msg));
2705 {
2706 FW->nFields = nFields;
2707 if (FW->nFields > 0) {
2708 FW->fLineNs = (int *) cdf_AllocateMemory (FW->nFields * sizeof(int),
2709 fatalFnc);
2710 FW->fCols = (int *) cdf_AllocateMemory (FW->nFields * sizeof(int),
2711 fatalFnc);
2712 FW->fLens = (int *) cdf_AllocateMemory (FW->nFields * sizeof(int),
2713 fatalFnc);
2714 }
2715 FW->NfLines = NfLines;
2716 if (FW->NfLines > 0) {
2717 int lineN, i;
2718 FW->fLines = (char **) cdf_AllocateMemory (FW->NfLines * sizeof(char *),
2719 fatalFnc);
2720 for (lineN = 0; lineN < FW->NfLines; lineN++) {
2721 FW->fLines[lineN] = (char *) cdf_AllocateMemory (fLineNchars+1,
2722 fatalFnc);
2723 for (i = 0; i < fLineNchars; i++) FW->fLines[lineN][i] = ' ';
2724 FW->fLines[lineN][fLineNchars] = NUL;
2725 }
2726 }
2727 return;
2728 }
2729
2730 /******************************************************************************
2731 * FreeIW.
2732 ******************************************************************************/
2733
FreeIW(IW,fatalFnc)2734 void FreeIW (IW, fatalFnc)
2735 struct ItemWindowStruct *IW;
2736 void (*fatalFnc) PROTOARGs((char *msg));
2737 {
2738 if (IW->NiLines > 0) {
2739 int lineN;
2740 for (lineN = IW->NiLines - 1; lineN >= 0; lineN--) {
2741 cdf_FreeMemory (IW->iLines[lineN], fatalFnc);
2742 }
2743 cdf_FreeMemory (IW->iLines, fatalFnc);
2744 }
2745 if (IW->nItems > 0) {
2746 cdf_FreeMemory (IW->iLens, fatalFnc);
2747 cdf_FreeMemory (IW->iCols, fatalFnc);
2748 cdf_FreeMemory (IW->iLineNs, fatalFnc);
2749 }
2750 IW->NiLines = 0;
2751 IW->nItems = 0;
2752 IW->iLines = NULL;
2753 IW->iLineNs = NULL;
2754 IW->iCols = NULL;
2755 IW->iLens = NULL;
2756 return;
2757 }
2758
2759 /******************************************************************************
2760 * FreeFW.
2761 ******************************************************************************/
2762
FreeFW(FW,fatalFnc)2763 void FreeFW (FW, fatalFnc)
2764 struct FieldWindowStruct *FW;
2765 void (*fatalFnc) PROTOARGs((char *msg));
2766 {
2767 if (FW->NfLines > 0) {
2768 int lineN;
2769 for (lineN = FW->NfLines - 1; lineN >= 0; lineN--) {
2770 cdf_FreeMemory (FW->fLines[lineN], fatalFnc);
2771 }
2772 cdf_FreeMemory (FW->fLines, fatalFnc);
2773 }
2774 if (FW->nFields > 0) {
2775 cdf_FreeMemory (FW->fLens, fatalFnc);
2776 cdf_FreeMemory (FW->fCols, fatalFnc);
2777 cdf_FreeMemory (FW->fLineNs, fatalFnc);
2778 }
2779 FW->NfLines = 0;
2780 FW->nFields = 0;
2781 FW->fLines = NULL;
2782 FW->fLineNs = NULL;
2783 FW->fCols = NULL;
2784 FW->fLens = NULL;
2785 return;
2786 }
2787
2788
2789 /******************************************************************************
2790 * OnlineHelpWindow.
2791 ******************************************************************************/
2792
OnlineHelpWindow(ilhFile,helpId)2793 Logical OnlineHelpWindow (ilhFile, helpId)
2794 char *ilhFile;
2795 int helpId;
2796 {
2797 AOSs1A (header, BLANKs78)
2798 AOSs1B (trailer,
2799 "Exit: ________ NextScreen: ________ PrevScreen: ________")
2800 static char errorLines[] = "Online help not available.\n";
2801 static int exitChars[] = { EXITkey_FSI, NUL };
2802 static char label[] = { BLANKs78 };
2803 static Logical first = TRUE;
2804 static struct EditWindowStruct EW = {
2805 label, 0, 0, SCREEN_WIDTH, 1, header, NULL, 18, 1, trailer, TRUE, TRUE,
2806 exitChars, REFRESHkey_FSI, NUL, NUL, NUL, NUL, NSkey_FSI, PSkey_FSI, NUL,
2807 NUL, NUL
2808 };
2809 /****************************************************************************
2810 * Encode label and key definitions the first time.
2811 ****************************************************************************/
2812 if (first) {
2813 sprintf (EW.label, " %s Online Help ", pgmName);
2814 EncodeKeyDefinitions (1, EW.tLines, EXITkey_FSI, NSkey_FSI, PSkey_FSI);
2815 first = FALSE;
2816 }
2817 /****************************************************************************
2818 * Load online help.
2819 ****************************************************************************/
2820 if (!LoadOnlineHelp(ilhFile,helpId,EW.hLines[0],&EW.eText)) {
2821 cdf_FreeMemory (EW.eText, FatalError);
2822 strcpyX (EW.hLines[0], "Error!", 0);
2823 EW.eText = errorLines;
2824 EditWindow (NEWew, &EW, TRUE);
2825 EditWindow (READew, &EW);
2826 EditWindow (DELETEew, &EW);
2827 return FALSE;
2828 }
2829 /****************************************************************************
2830 * Display help window/wait for exit key.
2831 ****************************************************************************/
2832 EditWindow (NEWew, &EW, TRUE);
2833 EditWindow (READew, &EW);
2834 EditWindow (DELETEew, &EW);
2835 /****************************************************************************
2836 * Cleanup and return.
2837 ****************************************************************************/
2838 cdf_FreeMemory (EW.eText, FatalError);
2839 return TRUE;
2840 }
2841
2842 /******************************************************************************
2843 * LoadOnlineHelp.
2844 * You'll notice that the buffers used to hold lines of online help are
2845 * allocated as (SCREEN_WIDTH-2)+1+1. This is for the number of characters,
2846 * the newline (as returned by `fgets'), and the terminating NUL character.
2847 * When `fgets' is called, the number of characters to read is specified as
2848 * (SCREEN_WIDTH-2)+1+1. This is for the actual characters plus the newline
2849 * plus one more since `fgets' subtracts one from this value and uses that as
2850 * the maximum number of characters to read (which includes the newline).
2851 ******************************************************************************/
2852
LoadOnlineHelp(ilhFile,helpId,header,eText)2853 Logical LoadOnlineHelp (ilhFile, helpId, header, eText)
2854 char *ilhFile;
2855 int helpId;
2856 char *header;
2857 char **eText;
2858 {
2859 FILE *fp; int i; size_t length;
2860 char beginStr[15+1], line[(SCREEN_WIDTH-2)+1+1], helpIdStr[15+1];
2861 enum { ITEMw, PROMPTw, EDITw } windowType;
2862 int nBlanks;
2863 int nestLevel = 0; /* Depth into `#ifos's. */
2864 int osMask = 0; /* When 0, display line. Note that bit 0 is not used
2865 (eg. nesting depth of 1 uses bit 1, etc.). */
2866 #if defined(vms)
2867 static char thisOS[] = "vms";
2868 #endif
2869 #if (defined(unix) && !defined(__CYGWIN__) && !defined(__MINGW32__)) || \
2870 defined(posixSHELL)
2871 static char thisOS[] = "unix";
2872 #endif
2873 #if defined(dos) || defined(__CYGWIN__) || defined(__MINGW32__)
2874 static char thisOS[] = "dos";
2875 #endif
2876 #if defined(mac)
2877 static char thisOS[] = "mac";
2878 #endif
2879 #if defined(win32)
2880 static char thisOS[] = "win";
2881 #endif
2882 /****************************************************************************
2883 * Initialize.
2884 ****************************************************************************/
2885 *eText = cdf_AllocateMemory ((size_t) 1, FatalError);
2886 MakeNUL (*eText);
2887 /****************************************************************************
2888 * Open help file.
2889 ****************************************************************************/
2890 fp = OnlineHelpFP (ilhFile, NULL);
2891 if (fp == NULL) return FALSE;
2892 /****************************************************************************
2893 * Read through help file looking for proper help section.
2894 ****************************************************************************/
2895 sprintf (beginStr, "#section %d", helpId);
2896 while (fgets(line,(SCREEN_WIDTH-2)+1+1,fp) != NULL) {
2897 /**************************************************************************
2898 * Strip trailing newline character and check to see if the help section
2899 * has been found.
2900 **************************************************************************/
2901 line[strlen(line)-1] = NUL;
2902 if (!strcmp(line,beginStr)) {
2903 /************************************************************************
2904 * Determine window type.
2905 ************************************************************************/
2906 if (fgets(line,(SCREEN_WIDTH-2)+1+1,fp) == NULL) {
2907 fclose (fp);
2908 return FALSE;
2909 }
2910 line[strlen(line)-1] = NUL;
2911 if (!strcmp(line,"#item"))
2912 windowType = ITEMw;
2913 else
2914 if (!strcmp(line,"#prompt"))
2915 windowType = PROMPTw;
2916 else
2917 if (!strcmp(line,"#edit"))
2918 windowType = EDITw;
2919 else {
2920 fclose (fp);
2921 return FALSE;
2922 }
2923 /************************************************************************
2924 * Build header.
2925 ************************************************************************/
2926 if (fgets(line,(SCREEN_WIDTH-2)+1+1,fp) == NULL) {
2927 fclose (fp);
2928 return FALSE;
2929 }
2930 line[strlen(line)-1] = NUL;
2931 if (strncmp(line,"#title ",7) != 0) {
2932 fclose (fp);
2933 return FALSE;
2934 }
2935 strcpyX (header, "Help for ", 0);
2936 strcatX (header, &line[7], 0);
2937 sprintf (helpIdStr, "[%d%c]", helpId,
2938 (windowType == ITEMw ? 'i' :
2939 (windowType == PROMPTw ? 'p' :
2940 (windowType == EDITw ? 'e' : '?'))));
2941 nBlanks = (SCREEN_WIDTH-2) - strlen(header) - strlen(helpIdStr);
2942 CatNcharacters (header, nBlanks, (int) ' ');
2943 strcatX (header, helpIdStr, 0);
2944 /************************************************************************
2945 * Read and save lines until "#endsection" is found.
2946 ************************************************************************/
2947 while (fgets(line,(SCREEN_WIDTH-2)+1+1,fp) != NULL) {
2948 line[strlen(line)-1] = NUL;
2949 /**********************************************************************
2950 * Check if at end of this section of help. If so, delete trailing
2951 * newline characters, encode key definitions based on window type,
2952 * close help file, and return.
2953 **********************************************************************/
2954 if (!strcmp(line,"#endsection")) {
2955 if (nestLevel != 0) {
2956 fclose (fp);
2957 return FALSE;
2958 }
2959 length = strlen (*eText);
2960 if (length > 0) {
2961 for (i = length - 1; i >= 0; i--) {
2962 if ((*eText)[i] != Nl) break;
2963 (*eText)[i] = NUL;
2964 }
2965 }
2966 switch (windowType) {
2967 case ITEMw:
2968 EncodeKeyDefinitions (1, eText, NSkey_FSI, PSkey_FSI);
2969 break;
2970 case PROMPTw:
2971 EncodeKeyDefinitions (1, eText, SOLkey_FSI, EOLkey_FSI,
2972 INSERTorOVERkey_FSI);
2973 break;
2974 case EDITw:
2975 EncodeKeyDefinitions (1, eText, NSkey_FSI, PSkey_FSI);
2976 break;
2977 }
2978 fclose (fp);
2979 return TRUE;
2980 }
2981 /**********************************************************************
2982 * Not at end yet. Check if an operating system directive. If not,
2983 * include the line if all of the bits in the operating system mask
2984 * are clear.
2985 **********************************************************************/
2986 if (line[0] == '#') {
2987 /********************************************************************
2988 * Check for an `#ifos' directive. If this operating system is not
2989 * specified, then set the bit in the operating system mask for this
2990 * nesting level.
2991 ********************************************************************/
2992 if (!strncmp(line,"#ifos",5)) {
2993 nestLevel++;
2994 if (strstr(line,thisOS) == NULL) SETBIT (osMask, nestLevel);
2995 continue;
2996 }
2997 /********************************************************************
2998 * Check for an `#else' directive. Simply flip the bit in the
2999 * operating system mask for this nesting level.
3000 ********************************************************************/
3001 if (!strcmp(line,"#else")) {
3002 if (nestLevel < 1) {
3003 fclose (fp);
3004 return FALSE;
3005 }
3006 FLPBIT (osMask, nestLevel);
3007 continue;
3008 }
3009 /********************************************************************
3010 * Check for an `#endos' directive. Clear the bit in the operating
3011 * system mask for this nesting level and decrement the nesting level.
3012 ********************************************************************/
3013 if (!strcmp(line,"#endos")) {
3014 if (nestLevel < 1) {
3015 fclose (fp);
3016 return FALSE;
3017 }
3018 CLRBIT (osMask, nestLevel);
3019 nestLevel--;
3020 continue;
3021 }
3022 /********************************************************************
3023 * An unknown directive has been encountered.
3024 ********************************************************************/
3025 fclose (fp);
3026 return FALSE;
3027 }
3028 else {
3029 if (osMask == 0) {
3030 size_t length, newLength;
3031 #if defined(dos)
3032 int tabCount, i;
3033 #endif
3034 length = strlen (line);
3035 #if defined(dos)
3036 for (tabCount = 0, i = 0; i < length; i++) {
3037 if (line[i] == Ht) tabCount++;
3038 }
3039 length += (7 * tabCount);
3040 #endif
3041 newLength = strlen(*eText) + (length + 1) + 1;
3042 *eText = cdf_ReallocateMemory (*eText, newLength,
3043 FatalError);
3044 #if defined(dos)
3045 for (i = 0; i < tabCount; i++) {
3046 strcatX (*eText, " ", 0);
3047 }
3048 strcatX (*eText, &line[i], 0);
3049 #else
3050 strcatX (*eText, line, 0);
3051 #endif
3052 strcatX (*eText, "\n", 0);
3053 }
3054 }
3055 }
3056 /************************************************************************
3057 * `#endsection' not found - error return.
3058 ************************************************************************/
3059 fclose (fp);
3060 return FALSE;
3061 }
3062 }
3063 /****************************************************************************
3064 * `#section x' not found - error return.
3065 ****************************************************************************/
3066 fclose (fp);
3067 return FALSE;
3068 }
3069
3070 /******************************************************************************
3071 * InfoWindow.
3072 ******************************************************************************/
3073
InfoWindow(message1,message2,message3,center,beep,wait)3074 void InfoWindow (message1, message2, message3, center, beep, wait)
3075 char *message1; /* This message line must exist. */
3076 char *message2; /* This message line is optional (NULL if absent). */
3077 char *message3; /* This message line is optional (NULL if absent).
3078 If `message2' is NULL, this must also be NULL. */
3079 Logical center; /* TRUE if window should be in center of screen. */
3080 Logical beep; /* TRUE if window should beep after being displayed. */
3081 int wait; /* 0: Read a key before deleting window.
3082 >0: Wait `wait' seconds and then delete window. */
3083 {
3084 static int exitChars[] = { NUL };
3085 static char eText[INFOtextMAX+1];
3086 static char ackLabel[] = " Enter any key to acknowledge. ";
3087 static struct EditWindowStruct EW = {
3088 NULL, 0, 0, 0, 0, NULL, eText, 0, 0, NULL, FALSE, TRUE, exitChars,
3089 REFRESHkey_FSI, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL
3090 };
3091 EW.label = BOO(wait > 0,NULL,ackLabel);
3092 if (center) {
3093 EW.nColsTotal = BOO(EW.label == NULL,0,(int)(strlen(EW.label) + 4));
3094 EW.nColsTotal = MaxInt (EW.nColsTotal, (int) (strlen(message1) + 2));
3095 strcpyX (EW.eText, message1, INFOtextMAX);
3096 strcatX (EW.eText, "\n", INFOtextMAX);
3097 EW.ULrow = (SCREEN_HEIGHT - 3) / 2;
3098 EW.NeRows = 1;
3099 if (message2 != NULL) {
3100 EW.nColsTotal = MaxInt (EW.nColsTotal, (int) (strlen(message2) + 2));
3101 strcatX (EW.eText, message2, INFOtextMAX);
3102 strcatX (EW.eText, "\n", INFOtextMAX);
3103 EW.ULrow = (SCREEN_HEIGHT - 4) / 2;
3104 EW.NeRows = 2;
3105 }
3106 if (message3 != NULL) {
3107 EW.nColsTotal = MaxInt (EW.nColsTotal, (int) (strlen(message3) + 2));
3108 strcatX (EW.eText, message3, INFOtextMAX);
3109 strcatX (EW.eText, "\n", INFOtextMAX);
3110 EW.ULrow = (SCREEN_HEIGHT - 5) / 2;
3111 EW.NeRows = 3;
3112 }
3113 EW.ULcol = (SCREEN_WIDTH - EW.nColsTotal) / 2;
3114 }
3115 else {
3116 strcpyX (EW.eText, message1, INFOtextMAX);
3117 strcatX (EW.eText, "\n", INFOtextMAX);
3118 EW.ULrow = SCREEN_HEIGHT - 3;
3119 EW.NeRows = 1;
3120 if (message2 != NULL) {
3121 strcatX (EW.eText, message2, INFOtextMAX);
3122 strcatX (EW.eText, "\n", INFOtextMAX);
3123 EW.ULrow = SCREEN_HEIGHT - 4;
3124 EW.NeRows = 2;
3125 }
3126 if (message3 != NULL) {
3127 strcatX (EW.eText, message3, INFOtextMAX);
3128 strcatX (EW.eText, "\n", INFOtextMAX);
3129 EW.ULrow = SCREEN_HEIGHT - 5;
3130 EW.NeRows = 3;
3131 }
3132 EW.nColsTotal = SCREEN_WIDTH;
3133 EW.ULcol = 0;
3134 }
3135 EditWindow (NEWew, &EW, TRUE);
3136 if (beep) EditWindow (BEEPew, &EW);
3137 if (wait > 0)
3138 zzzzz ((double) wait);
3139 else
3140 EditWindow (READew, &EW);
3141 EditWindow (DELETEew, &EW);
3142 return;
3143 }
3144