form.c revision 1.8 1 /* $NetBSD: form.c,v 1.8 2001/05/16 11:51:16 blymn Exp $ */
2
3 /*-
4 * Copyright (c) 1998-1999 Brett Lymn
5 * (blymn (at) baea.com.au, brett_lymn (at) yahoo.com.au)
6 * All rights reserved.
7 *
8 * This code has been donated to The NetBSD Foundation by the Author.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. The name of the author may not be used to endorse or promote products
16 * derived from this software withough specific prior written permission
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 coda test.
30 *
31 */
32
33 #include <stdlib.h>
34 #include <strings.h>
35 #include <form.h>
36 #include "internals.h"
37
38 extern FIELD _formi_default_field;
39
40 FORM _formi_default_form = {
41 FALSE, /* true if performing a init or term function */
42 FALSE, /* the form is posted */
43 FALSE, /* make field list circular if true */
44 NULL, /* window for the form */
45 NULL, /* subwindow for the form */
46 NULL, /* use this window for output */
47 NULL, /* user defined pointer */
48 0, /* options for the form */
49 NULL, /* function called when form posted and
50 after page change */
51 NULL, /* function called when form is unposted and
52 before page change */
53 NULL, /* function called when form posted and after
54 current field changes */
55 NULL, /* function called when form unposted and
56 before current field changes */
57 0, /* number of fields attached */
58 0, /* current field */
59 0, /* current page of form */
60 0, /* number of pages in the form */
61 NULL, /* dynamic array of fields that start
62 the pages */
63 {NULL, NULL}, /* sorted field list */
64 NULL /* array of fields attached to this form. */
65 };
66
67 /*
68 * Set the window associated with the form
69 */
70 int
71 set_form_win(FORM *form, WINDOW *win)
72 {
73 if (form == NULL) {
74 _formi_default_form.win = win;
75 _formi_default_form.scrwin = win;
76 } else {
77 if (form->posted == TRUE)
78 return E_POSTED;
79 else {
80 form->win = win;
81 form->scrwin = win;
82 }
83 }
84
85 return E_OK;
86 }
87
88 /*
89 * Return the window used by the given form
90 */
91 WINDOW *
92 form_win(FORM *form)
93 {
94 if (form == NULL)
95 return _formi_default_form.win;
96 else
97 return form->win;
98 }
99
100 /*
101 * Set the subwindow for the form.
102 */
103 int
104 set_form_sub(FORM *form, WINDOW *window)
105 {
106 if (form == NULL) {
107 _formi_default_form.subwin = window;
108 _formi_default_form.scrwin = window;
109 } else {
110 if (form->posted == TRUE)
111 return E_POSTED;
112 else {
113 form->subwin = window;
114 form->scrwin = window;
115 }
116 }
117
118 return E_OK;
119 }
120
121 /*
122 * Return the subwindow for the given form.
123 */
124 WINDOW *
125 form_sub(FORM *form)
126 {
127 if (form == NULL)
128 return _formi_default_form.subwin;
129 else
130 return form->subwin;
131 }
132
133 /*
134 * Return the minimum size required to contain the form.
135 */
136 int
137 scale_form(FORM *form, int *rows, int *cols)
138 {
139 int i, max_row, max_col, temp;
140
141 if ((form->fields == NULL) || (form->fields[0] == NULL))
142 return E_NOT_CONNECTED;
143
144 max_row = 0;
145 max_col = 0;
146
147 for (i = 0; i < form->field_count; i++) {
148 temp = form->fields[i]->form_row + form->fields[i]->rows;
149 max_row = (temp > max_row)? temp : max_row;
150 temp = form->fields[i]->form_col + form->fields[i]->cols;
151 max_col = (temp > max_col)? temp : max_col;
152 }
153
154 (*rows) = max_row;
155 (*cols) = max_col;
156
157 return E_OK;
158 }
159
160 /*
161 * Set the user defined pointer for the form given.
162 */
163 int
164 set_form_userptr(FORM *form, void *ptr)
165 {
166 if (form == NULL)
167 _formi_default_form.userptr = ptr;
168 else
169 form->userptr = ptr;
170
171 return E_OK;
172 }
173
174 /*
175 * Return the user defined pointer associated with the given form.
176 */
177 void *
178 form_userptr(FORM *form)
179 {
180
181 if (form == NULL)
182 return _formi_default_form.userptr;
183 else
184 return form->userptr;
185 }
186
187 /*
188 * Set the form options to the given ones.
189 */
190 int
191 set_form_opts(FORM *form, Form_Options options)
192 {
193 if (form == NULL)
194 _formi_default_form.opts = options;
195 else
196 form->opts = options;
197
198 return E_OK;
199 }
200
201 /*
202 * Turn the given options on for the form.
203 */
204 int
205 form_opts_on(FORM *form, Form_Options options)
206 {
207 if (form == NULL)
208 _formi_default_form.opts |= options;
209 else
210 form->opts |= options;
211
212 return E_OK;
213 }
214
215 /*
216 * Turn the given options off for the form.
217 */
218 int
219 form_opts_off(FORM *form, Form_Options options)
220 {
221 if (form == NULL)
222 _formi_default_form.opts &= ~options;
223 else
224 form->opts &= ~options;
225
226
227 return E_OK;
228 }
229
230 /*
231 * Return the options set for the given form.
232 */
233 Form_Options
234 form_opts(FORM *form)
235 {
236 if (form == NULL)
237 return _formi_default_form.opts;
238 else
239 return form->opts;
240 }
241
242 /*
243 * Set the form init function for the given form
244 */
245 int
246 set_form_init(FORM *form, Form_Hook func)
247 {
248 if (form == NULL)
249 _formi_default_form.form_init = func;
250 else
251 form->form_init = func;
252
253 return E_OK;
254 }
255
256 /*
257 * Return the init function associated with the given form.
258 */
259 Form_Hook
260 form_init(FORM *form)
261 {
262 if (form == NULL)
263 return _formi_default_form.form_init;
264 else
265 return form->form_init;
266 }
267
268 /*
269 * Set the function to be called on form termination.
270 */
271 int
272 set_form_term(FORM *form, Form_Hook function)
273 {
274 if (form == NULL)
275 _formi_default_form.form_term = function;
276 else
277 form->form_term = function;
278
279 return E_OK;
280 }
281
282 /*
283 * Return the function defined for the termination function.
284 */
285 Form_Hook
286 form_term(FORM *form)
287 {
288
289 if (form == NULL)
290 return _formi_default_form.form_term;
291 else
292 return form->form_term;
293 }
294
295
296 /*
297 * Attach the given fields to the form.
298 */
299 int
300 set_form_fields(FORM *form, FIELD **fields)
301 {
302 int num_fields = 0, i, maxpg = 1, status;
303
304 if (form == NULL)
305 return E_BAD_ARGUMENT;
306
307 if (form->posted == TRUE)
308 return E_POSTED;
309
310 if (fields == NULL)
311 return E_BAD_ARGUMENT;
312
313 while (fields[num_fields] != NULL) {
314 if ((fields[num_fields]->parent != NULL) &&
315 (fields[num_fields]->parent != form))
316 return E_CONNECTED;
317 num_fields++;
318 }
319
320 /* disconnect old fields, if any */
321 if (form->fields != NULL) {
322 for (i = 0; i < form->field_count; i++) {
323 form->fields[i]->parent = NULL;
324 form->fields[i]->index = -1;
325 }
326 }
327
328 /* kill old page pointers if any */
329 if (form->page_starts != NULL)
330 free(form->page_starts);
331
332 form->field_count = num_fields;
333
334 /* now connect the new fields to the form */
335 for (i = 0; i < num_fields; i++) {
336 fields[i]->parent = form;
337 fields[i]->index = i;
338 /* set the page number of the field */
339 if (fields[i]->page_break == 1)
340 maxpg++;
341 fields[i]->page = maxpg;
342 }
343
344 form->fields = fields;
345 form->cur_field = 0;
346 form->max_page = maxpg;
347 if ((status = _formi_find_pages(form)) != E_OK)
348 return status;
349
350 /* sort the fields and set the navigation pointers */
351 _formi_sort_fields(form);
352 _formi_stitch_fields(form);
353
354 return E_OK;
355 }
356
357 /*
358 * Return the fields attached to the form given.
359 */
360 FIELD **
361 form_fields(FORM *form)
362 {
363 if (form == NULL)
364 return NULL;
365
366 return form->fields;
367 }
368
369 /*
370 * Return the number of fields attached to the given form.
371 */
372 int
373 field_count(FORM *form)
374 {
375 if (form == NULL)
376 return -1;
377
378 return form->field_count;
379 }
380
381 /*
382 * Move the given field to the row and column given.
383 */
384 int
385 move_field(FIELD *fptr, int frow, int fcol)
386 {
387 FIELD *field = (fptr == NULL) ? &_formi_default_field : fptr;
388
389 if (field->parent != NULL)
390 return E_CONNECTED;
391
392 field->form_row = frow;
393 field->form_col = fcol;
394
395 return E_OK;
396 }
397
398 /*
399 * Set the page of the form to the given page.
400 */
401 int
402 set_form_page(FORM *form, int page)
403 {
404 if (form == NULL)
405 return E_BAD_ARGUMENT;
406
407 if (form->in_init == TRUE)
408 return E_BAD_STATE;
409
410 if (page > form->max_page)
411 return E_BAD_ARGUMENT;
412
413 form->page = page;
414 return E_OK;
415 }
416
417 /*
418 * Return the maximum page of the form.
419 */
420 int
421 form_max_page(FORM *form)
422 {
423 if (form == NULL)
424 return _formi_default_form.max_page;
425 else
426 return form->max_page;
427 }
428
429 /*
430 * Return the current page of the form.
431 */
432 int
433 form_page(FORM *form)
434 {
435 if (form == NULL)
436 return -1;
437
438 return form->page;
439 }
440
441 /*
442 * Set the current field to the field given.
443 */
444 int
445 set_current_field(FORM *form, FIELD *field)
446 {
447 if (form == NULL)
448 return E_BAD_ARGUMENT;
449
450 if (form->in_init == TRUE)
451 return E_BAD_STATE;
452
453 if (field == NULL)
454 return E_INVALID_FIELD;
455
456 if ((field->parent == NULL) || (field->parent != form))
457 return E_INVALID_FIELD; /* field is not of this form */
458
459 form->cur_field = field->index;
460 return E_OK;
461 }
462
463 /*
464 * Return the current field of the given form.
465 */
466 FIELD *
467 current_field(FORM *form)
468 {
469 if (form == NULL)
470 return NULL;
471
472 if (form->fields == NULL)
473 return NULL;
474
475 return form->fields[form->cur_field];
476 }
477
478 /*
479 * Allocate a new form with the given fields.
480 */
481 FORM *
482 new_form(FIELD **fields)
483 {
484 FORM *new;
485
486 if ((new = (FORM *) malloc(sizeof(FORM))) == NULL)
487 return NULL;
488
489
490 /* copy in the defaults... */
491 bcopy(&_formi_default_form, new, sizeof(FORM));
492
493 if (new->win == NULL)
494 new->scrwin = stdscr; /* something for curses to write to */
495
496 if (fields != NULL) { /* attach the fields, if any */
497 if (set_form_fields(new, fields) < 0) {
498 free(new); /* field attach failed, back out */
499 return NULL;
500 }
501 }
502
503 return new;
504 }
505
506 /*
507 * Free the given form.
508 */
509 int
510 free_form(FORM *form)
511 {
512 int i;
513
514 if (form == NULL)
515 return E_BAD_ARGUMENT;
516
517 if (form->posted == TRUE)
518 return E_POSTED;
519
520 for (i = 0; i < form->field_count; i++) {
521 /* detach all the fields from the form */
522 form->fields[i]->parent = NULL;
523 form->fields[i]->index = -1;
524 }
525
526 free(form->fields);
527 free(form);
528
529 return E_OK;
530 }
531
532 /*
533 * Tell if the current field of the form has offscreen data ahead
534 */
535 int
536 data_ahead(FORM *form)
537 {
538 FIELD *cur;
539
540 if ((form == NULL) || (form->fields == NULL)
541 || (form->fields[0] == NULL))
542 return FALSE;
543
544 cur = form->fields[form->cur_field];
545
546 if (cur->lines[cur->start_line + cur->cursor_ypos].length > cur->cols)
547 return TRUE;
548
549 return FALSE;
550 }
551
552 /*
553 * Tell if current field of the form has offscreen data behind
554 */
555 int
556 data_behind(FORM *form)
557 {
558 FIELD *cur;
559
560 if ((form == NULL) || (form->fields == NULL)
561 || (form->fields[0] == NULL))
562 return FALSE;
563
564 cur = form->fields[form->cur_field];
565
566 if (cur->start_char > 0)
567 return TRUE;
568
569 return FALSE;
570 }
571
572 /*
573 * Position the form cursor.
574 */
575 int
576 pos_form_cursor(FORM *form)
577 {
578 FIELD *cur;
579 int row, col;
580
581 if ((form == NULL) || (form->fields == NULL) ||
582 (form->fields[0] == NULL))
583 return E_BAD_ARGUMENT;
584
585 if (form->posted != 1)
586 return E_NOT_POSTED;
587
588 cur = form->fields[form->cur_field];
589 row = cur->form_row;
590 col = cur->form_col;
591
592 /* if the field is public then show the cursor pos */
593 if ((cur->opts & O_PUBLIC) == O_PUBLIC) {
594 row += cur->cursor_ypos;
595 col += cur->cursor_xpos;
596 if (cur->cursor_xpos >= cur->cols) {
597 col = cur->form_col;
598 row++;
599 }
600 }
601
602 #ifdef DEBUG
603 fprintf(dbg, "pos_cursor: row=%d, col=%d\n", row, col);
604 #endif
605
606 wmove(form->scrwin, row, col);
607
608 return E_OK;
609 }
610